🐻

Supabaseをローカル環境に構築してNext.jsアプリで利用する(後半)

2022/03/11に公開

前回の記事に引き続き、Next.jsのアプリで、ローカル環境に立ち上げたSupbaseを利用する手順を紹介します。

https://zenn.dev/hrtk/articles/supabase-nextjs-local

プロフィール編集を追加

こちらの記事のコードを流用します。

https://zenn.dev/hrtk/articles/supabase-nextjs-database-authorization

本記事では、コードの内容に関しては詳しくは触れないので、上記の記事を参考にしてください。

テーブルを追加

ローカルに立ち上げているSupbase Studioに接続して、プロジェクトのダッシュボードを開きます。

http://localhost:54323/

SQL Editorを開いて、SQL Queryに次にSQLを入力して実行します。

-- publicにprofilesテーブルを作成
create table profiles (
  id uuid references auth.users not null,
  updated_at timestamp with time zone,
  name text,

  primary key (id)
);

alter table profiles enable row level security;

create policy "パブリックなプロフィールはだれでも参照(select)できる。"
  on profiles for select
  using ( true );

create policy "自身のプロフィールを更新(update)できる。"
  on profiles for update
  using ( auth.uid() = id );

create policy "自身のプロフィールを追加(insert)できる。"
  on profiles for insert
  with check ( auth.uid() = id );

コンポーネントを追加

前回のコードに、プロフィール更新のコンポーネントを追加します。

components/profile.tsx
import { useState } from 'react'
import { useUser } from '@/contexts/user'
import { supabase } from '@/lib/supabase-client'

export default function Profile() {
  const { user, setUser } = useUser()
  const [loading, setLoading] = useState()
  const [name, setName] = useState(user.profile && user.profile.name)

  async function updateProfile({ name }) {
    try {
      setLoading(true)
      const user = supabase.auth.user()

      const updates = {
        id: user.id,
        name,
        updated_at: new Date(),
      }

      const { data: profile, error } = await supabase
        .from('profiles')
        .upsert(updates)
        .single()

      if (error) {
        throw error
      } else {
        alert('プロフィールを更新しました!')
        setUser({ ...user, profile })
      }
    } catch (error) {
      alert(error.message)
    } finally {
      setLoading(false)
    }
  }

  return (
    <div className="mt-6">
      <label className="block">名前</label>
      <input
        id="name"
        className="w-full mt-2"
        type="text"
        value={name || ''}
        onChange={(e) => setName(e.target.value)}
      />
      <button
        className="primary mt-4 mr-4"
        onClick={() => updateProfile({ name })}
        disabled={loading}
      >
        {loading ? '読み込み中...' : '更新'}
      </button>
    </div>
  )
}

ダッシュボードにコンポーネントを追加します。

components/dasboard.tsx
@@ -1,4 +1,5 @@
 import { useUser } from '@/contexts/user'
+import Profile from '@/components/profile'
 
 export default function Dashboard() {
   const { logout, user } = useUser()
@@ -9,6 +10,7 @@ export default function Dashboard() {
       <div className="mt-6">
         <p>Hello, {user.email}!</p>
       </div>
+      <Profile />
       <div className="mt-6">
         <button className="secondary" onClick={() => logout()}>
           ログアウト

ログインして、プロフィールを更新できることを確認します。

マイグレーション

Supabaseの1つの魅力として、Table Editorでテーブルの追加や、カラムの追加、変更が手軽に行えることが挙げられます。ただ、手作業で行った修正を同じように本番環境へ適用したり、チームのメンバーへ展開するのが難しくなります。

その手間を軽減するため、Supabase CLIではマイグレーション機能を提供しています。

db commitすることで、先ほど追加したテーブルをマイグレーションファイルとして出力します。

supbaseコマンドを次にように実行します。

supabase db commit add_profiles

引数で指定しているadd_profilesは、ファイル名に追記される文字列です。どのような変更をしたのか推測しやすい内容にします。

実行するとsupabase/migrationsディレクトリにファイルが出力されます。

$ ls -la supabase/migrations/
total 8
drwxr-xr-x  3 hirotaka  staff    96  3 10 18:15 .
drwxr-xr-x  8 hirotaka  staff   256  3 11 14:34 ..
-rw-r--r--  1 hirotaka  staff  1591  3 10 18:15 20220310022310_add_profiles.sql

ファイル名の最初はそれぞれ実行したタイミングで異なってきます。

マイグレーションファイルは、Gitでアプリのコードと一緒にリポジトリーで管理するようにします。

そうすることで、チーム内の各メンバーがローカルに構築した環境のデータベース構造を共有できるようになります。

シード

前回の記事でも触れたのですが、Dockerの特性上、コンテナを停止するとデータベースのデータはなくなってしまいます。

立ち上げる度にユーザーを作成するのは手間なので、動作確認して作成したデータをシードとして保存しておきます。

先ほど作成したprofilesテーブルと、authスキーマにあるusersテーブルのデータをシードとして保存します。

authスキーマ内にはSupabase Authで使用するテーブル類があります。だいたいは、トランザクション的なデータなのでusersテーブルだけ出力します。

ここでは、Postgresに付随しているpg_dumpコマンドを使用して出力する手順を紹介します。

Postgresがインストールされていない場合は、Macであればbrew経由でインストールできます。

brew install posgresql

その他のプラットフォームは次を参考にしくてださい。

https://www.postgresql.jp/download

ターミナルで次のように実行します。

pg_dump -h localhost -p 54322 -d postgres -U postgres \
  --table='auth.users' \
  --table='profiles' \
  --data-only \
  --inserts > supabase/seed.sql

シードはSupbaseを立ち上げた際に自動で実行されます。これで、停止して立ち上げ直してもデータが保持されていることを確認できます。

ここまでのコードは次で確認できます。

https://github.com/hirotaka/examples/tree/baghdad-0.0.3/supabase-nextjs-local

本番への反映

ローカル環境で一通り動作の確認ができたら、本番へも適用する必要があります。

まず、本番環境のデータベースをセットします。

「Settings」ページで、サイドメニューから「Database」を選択します。

下の方の「Connection string」欄で、「URI」タブを選択します。

「Copy」ボタンをクリックして、表示されている文字列をコピーします。

[YOUR-PASSWORD]となっている箇所は、データベースを作成した際に指定したパスワードへ置き換えて、ターミナルで次のようにします。

supabase db remote set 'postgresql://postgres:[YOUR-PASSWORD]@db.nohlprxiarskrxribmay.supabase.co:5432/postgres'

設定した内容は、supabase/.envに保存されます。このファイルは機密情報なので、レポジトリーにコミットしたり、外部に漏れないように十分気をつけてください。

これで、次のコマンドを実行することで、マイグレーションを本番に反映できます。

supabase db push

実際には、手動で実行するよりも、CI/CDでデプロイする際に実行するといいでしょう。

おわりに

Supbaseは、プロジェクトを作成して、すぐにプロダクトづくりのための環境ができるのは魅力です。Supbaseのダッシュボードで簡単にテーブルを作成、カラムを追加や変更したりできます。

ただ、Supbaseでは無料で作成できるプロジェクトが限られています。チームで開発する際、開発用の環境は共有にするか、各メンバー用に開発環境のコストを支払う必要があります。

ローカル環境でSupabseを立ち上げて開発することで、効率を落とすことなくコストを抑えることができます。

参考

Supbaseの知識を深めるために、ドキュメントの翻訳に取り組んでいます。

https://supabase.jp/

ローカル開発環境について、こちらも参考にしてください。

https://supabase.jp/docs/guides/local-development

GitHubで編集を提案

Discussion