Open5

Next.js、prisma、supabaseでユーザー投稿

▲

Prismaの導入

prismaと@prisma/clientをインストール

npm install prisma --save-dev

npm install @prisma/client

ファイルを作成し、以下を記述

src/lib/prisma.ts
import { PrismaClient } from "@prisma/client";

const prismaClientSingleton = () => {
  return new PrismaClient();
};

declare const globalThis: {
  prismaGlobal: ReturnType<typeof prismaClientSingleton>;
} & typeof global;

const prisma = globalThis.prismaGlobal ?? prismaClientSingleton();

export default prisma;

if (process.env.NODE_ENV !== "production") globalThis.prismaGlobal = prisma;

▲

Prismaの初期化

以下のコマンドを実行しPrismaの初期化をする

npx prisma init

初期化すると prisma/schema.prisma.envファイルが作られる。
既存の.envが存在していれば、それにDATABASE_URLの環境変数が追加される

DATABASE_URLはsupabaseのURLに変更する必要がある。
ヘッダー部分にある「Connect」をクリックするとモーダルが開く。
その中の「ORMs」タブを開きPrismaを選択 .env.local.envファイルに追記。
[YOUR-PASSWORD] の部分は最初に設定したDBパスワードを指定
prisma/schema.prisma もタブに書かれているない様に変更( directUrl = env("DIRECT_URL") を追記)

▲

migrate

prisma/schema.prisma に以下を追加。
公式ドキュメント参照

ドキュメントのidはintだが、UUIDを使う様にしたためstringに

model User {
 id    String  @id 
 email String  @unique
 name  String?
 posts Post[]
}

model Post {
 id        Int     @id @default(autoincrement())
 title     String
 content   String?
 published Boolean @default(false)
 author    User    @relation(fields: [authorId], references: [id])
 authorId  String 
}

以下を実行すると prisma/migrations が生成される

npx prisma migrate dev --name init

管理画面のTable Editorでは定義したDBのテーブルが追加されている

▲

POST

以下のようなpostする処理を書く。
適当にフォームや送信ボタンを作って送信するとDBに保存される

const createPost = async (formData: FormData) => {
    "use server";

    const title = formData.get("title") as string;
    const content = formData.get("content") as string;

    if (!title) return;

    const supabaseServer = await createClient();
    const { data: { user: currentUser } } = await supabaseServer.auth.getUser();

    if (!currentUser?.id) return;

    let dbUser = await prisma.user.findUnique({
      where: { id: currentUser.id }
    });

    if (!dbUser) {
      dbUser = await prisma.user.create({
        data: {
          id: currentUser.id,
          email: currentUser.email || "",
          name: currentUser.user_metadata?.full_name || null
        }
      });
    }

    await prisma.post.create({ 
      data: { 
        title, 
        content, 
        authorId: currentUser.id 
      } 
    });

    revalidatePath("/dashboard");
  };
▲

一覧を取得

以下を書くとuserPostsに投稿データが格納されるので、mapすると一覧が表示される

 // ログインユーザーの投稿を取得
  let userPosts: any[] = [];
  if (user?.id) {
    userPosts = await prisma.post.findMany({
      where: {
        authorId: user.id
      },
      orderBy: {
        createdAt: 'desc'
      },
      include: {
        author: {
          select: {
            name: true,
            email: true
          }
        }
      }
    });
  }