狐好きぷろぐらまー

狐好きぷろぐらまー

狐好きプログラマーのブログです。

【Supabase】パスワード設定済みのテストユーザーをseed.sqlで生成する方法【Local Dev】

こんにちは。pregum_foxです。

今回は備忘録なので短めです。

背景

ローカルの開発環境にて、毎回ユーザーを作成するのが大変なので、seed.sqlに固定したパスワードとメールアドレスで生成されるユーザーをsupabase db resetコマンドを叩くと自動で生成されるようにしたかったので、調査しました。

前提条件

  • dockerが起動していること
  • supabase initコマンドが実行されてsupabase/config.tomlファイルが生成されていること
  • Supabase CLIがインストールされていること
  • 設定するプロジェクトでemailのproviderが有効になっていること
    • 具体的には以下のような設定になっていればOKです

環境

結論

seed.sqlが読み込めるようにconfig.tomlの最後にseed.sqlファイルを読み込む設定を追加します。

https://supabase.com/docs/guides/local-development/seeding-your-database

       # 記述されている設定...
         # ↓ を追加
         [db.seed]
   enabled = true
   sql_paths = ['./seeds/*.sql']

supabase/seeds/seed.sqlに以下の関数を書いて呼び出すことで実行できました。

Can't seed or signup auth users locally · supabase · Discussion #9251 · GitHub

     -- ============================================
  -- 1. 拡張機能とヘルパー関数の定義
  -- ============================================
  CREATE EXTENSION IF NOT EXISTS "pgcrypto";
  
  -- 関数はこちらのコードをお借りした
  -- ref: https://github.com/orgs/supabase/discussions/9251#discussioncomment-6199552
  -- パスワード付きのユーザーを作成する関数
  CREATE OR REPLACE FUNCTION public.create_user_for_test(
      email text,
      password text
  ) RETURNS uuid AS $$
    declare
    user_id uuid;
    encrypted_pw text;
  BEGIN
    user_id := gen_random_uuid();
    encrypted_pw := crypt(password, gen_salt('bf'));
    
    INSERT INTO auth.users
      (instance_id, id, aud, role, email, encrypted_password, email_confirmed_at, recovery_sent_at, last_sign_in_at, raw_app_meta_data, raw_user_meta_data, created_at, updated_at, confirmation_token, email_change, email_change_token_new, recovery_token)
    VALUES
      ('00000000-0000-0000-0000-000000000000', user_id, 'authenticated', 'authenticated', email, encrypted_pw, '2023-05-03 19:41:43.585805+00', '2023-04-22 13:10:03.275387+00', '2023-04-22 13:10:31.458239+00', '{"provider":"email","providers":["email"]}', '{}', '2023-05-03 19:41:43.580424+00', '2023-05-03 19:41:43.585948+00', '', '', '', '');
    
    INSERT INTO auth.identities (id, user_id, identity_data, provider, last_sign_in_at, created_at, updated_at, provider_id)
    VALUES
      (gen_random_uuid(), user_id, format('{"sub":"%s","email":"%s"}', user_id::text, email)::jsonb, 'email', '2023-05-03 19:41:43.582456+00', '2023-05-03 19:41:43.582497+00', '2023-05-03 19:41:43.582497+00', email);
  
    RETURN user_id;
  END;
  $$ LANGUAGE plpgsql;

実際に呼び出す場合はdoブロックで囲む必要があるので注意です。 doブロックで囲まないと、failed to send batch: ERROR: function public.create_user_for_test(text, text) does not exist (SQLSTATE 42883) のようなエラーメッセージが表示され実行ができませんでした。

https://github.com/supabase/cli/issues/882#issuecomment-1595725535

下記の例では、以下の2つのusersレコードを作成しています。

  • email: dev1@example.com, password: password123
  • email: dev2@example.com, password: password123
     -- ============================================
     -- 3. 開発用データの作成
     -- ============================================
     -- 開発用のテストユーザーを追加(既存のテストユーザーに加えて)
     -- seed.sql内で関数を実行する場合は、doブロックで囲む必要があった
     -- ref: https://github.com/supabase/cli/issues/882#issuecomment-1595725535
     do $$
     begin
     -- ユーザーの作成
     perform public.create_user_for_test('dev1@example.com'::text, 'password123'::text);
     perform public.create_user_for_test('dev2@example.com'::text, 'password123'::text);
     end $$;

生成したuser_idに対して何かしらのデータを紐付けたい場合は、doブロック内で変数を定義して、sqlを書くことで作成できました。

イメージ

-- ============================================
-- 3. 開発用データの作成
-- ============================================
-- 開発用のテストユーザーを追加(既存のテストユーザーに加えて)
-- seed.sql内で関数を実行する場合は、doブロックで囲む必要がありました
-- ref: https://github.com/supabase/cli/issues/882#issuecomment-1595725535
do $$
declare
    dev1_user_id uuid;
    dev2_user_id uuid;
    dev1_exhibition_id int;
begin
    -- ユーザーの作成
    dev1_user_id := public.create_user_for_test('dev1@example.com'::text, 'password123'::text);
    dev2_user_id := public.create_user_for_test('dev2@example.com'::text, 'password123'::text);

    -- dev1の展示会を作成
    INSERT INTO public.exhibitions (
        name,
        description,
        author_user_id,
        start_at,
        end_at,
        location,
        created_at,
        updated_at
    ) VALUES (
        '開発用展示会1',
        '開発ユーザー1の展示会です',
        dev1_user_id,
        '2024-01-01 00:00:00+00',
        '2024-12-31 23:59:59+00',
        '開発美術館',
        NOW(),
        NOW()
    ) RETURNING id INTO dev1_exhibition_id;

    -- dev1の作品を作成
    INSERT INTO public.artworks (
        name,
        description,
        artist_name,
        author_user_id,
        exhibition_id,
        created_at,
        updated_at
    ) VALUES (
        '開発用作品1',
        '開発用展示会1の作品1です',
        '開発作家1',
        dev1_user_id,
        dev1_exhibition_id,
        NOW(),
        NOW()
    );

    -- 作品の画像を追加
    INSERT INTO public.artwork_images (
        image_url,
        storage_file_path,
        artwork_id,
        created_at
    ) VALUES (
        'https://example.com/dev/artworks/1/image1.jpg',
        'dev/artworks/1/image1.jpg',
        currval('public.artworks_id_seq'),
        NOW()
    );
end $$;

seed.sql内の記述順は以下の順番であれば実行できました。

  1. 関数
  2. 関数呼び出し

sqlの変更が完了したら、supabase db reset でseed.sqlを実行し直して、スキーマ、テーブルのレコードを作り直すことで反映が可能です。

手元のFlutterのアプリにてログインできることを確認しました。

もしローカル環境のレコード内にバックアップをとっておきたいデータがある場合は、先にpg_dumpコマンドやTable Plusのexportなどで保存しておくことを推奨します。

ここまで読んでいただきありがとうございます。

【ESET】Androidにてlocalhostに対してのhttp接続ができなかった時の対応メモ【ファイアーウォール】

こんにちは。pregum_foxです。 今回は実機のAndroid端末からローカルPCへ向けてのhttp接続が動作しないことがあり、一般的なハマりポイントとは異なる箇所でハマっていたので、備忘録としてこちらに残しておこうと思います。

以下目次です。

  • 開発環境
  • 概要
  • 原因
  • 解決方法
  • 調査時に行ったこと
  • 雑感
  • 参考URL
続きを読む

Git操作のストレスを解消!lazygitで快適なバージョン管理を

こんにちは。 pregum_foxです。

最近tigを使ってGitの操作をしていましたが、最近はlazygitに乗り換えてみて直接gitコマンドを打つ頻度が減ってきました。

この記事では以下の内容を紹介します。

  • lazygitとは
  • なぜlazygitを使うのか
  • lazygitの設定手順
    • 日本語化
    • キーバインドのカスタマイズ
    • 現在の設定ファイルの内容
  • lazygitで操作する方法
    • 基本的なgitコマンド
    • よく使うシナリオ

以下目次です。

  • この記事を読むことでわかること
  • 対象外の内容
  • 想定読者
  • 動作確認環境
  • lazygitとは
  • 背景
  • lazygitを使用するメリット
  • lazygitの設定方法と使い方
    • インストール方法
    • 基本的な設定
      • 日本語化の設定
      • アイコンの設定
      • キーバインドのカスタマイズ
      • よく使うキー操作
      • おすすめの設定ファイル
    • よく使うコマンド一覧
    • コマンドごとの操作方法
      • git add ~
        • git add {ファイルパス} | 対象ファイルのステージング
        • git add -A | 全てのファイルのステージング
      • git commit ~
        • git commit -m {メッセージ} | コミットメッセージの設定
        • git commit --amend | コミットメッセージの修正
        • git commit | 標準エディタでコミットメッセージの設定
      • git push ~
        • git push {取得先のremote} {ブランチ名} | ブランチのプッシュ
        • git push --force | 強制プッシュ
      • git pull ~
        • git pull | ブランチのプル
      • git checkout ~ (git restore関連)
        • git checkout . | git restore . | 変更を元に戻す
      • git checkout ~ (git switch関連)
        • git checkout {ブランチ名} | git switch {ブランチ名} | フランチの切り替え
        • git checkout {リモートに存在するブランチ名} | リモートブランチのチェックアウト
      • git branch ~
        • git branch -d {ブランチ名} | ブランチの削除
      • git merge ~
        • git merge {ブランチ名} | ブランチのマージ
      • git rebase ~
        • git rebase {ブランチ名} | ブランチのリベース
        • git rebase -i {コミットID or ブランチ名} | 対象のコミット以降のインタラクティブなリベース
      • git reset ~
        • git reset {コミットID} | 現在のブランチのHEADを移動
      • git stash ~
        • git stash push | ステージングしていない変更をスタッシュ
        • git stash pop | スタッシュのポップ(適用後stash一覧から破棄)
        • git stash drop | スタッシュの削除
        • git stash apply | スタッシュの適用
        • git stash drop & store | スタッシュメッセージの変更
      • git tag ~
        • git tag {タグ名} | タグの作成
      • git revert ~
        • git revert {コミットID} | コミットの取り消し
      • git cherry-pick ~
        • git cherry-pick {コミットID} | コミットの適用
      • コンフリクトの解消
    • 実践ケース集
      • lazygitの設定ファイルを編集するケース
      • 新機能の開発を始めるケース
      • コミットした後にコミットメッセージを変えて再度pushするケース
      • コミットした直後にフォーマッタの差分が出ていたので最新のコミットに混ぜ込むケース
      • 切り出し元のブランチが更新されたのでその差分を作業中のブランチにリベース(or マージ) するケース
        • リベースの場合
        • マージの場合
      • 何らかの作業を行う前に一部分の差分だけstashするケース
      • コミットのURL(or SHA-1)をクリップボードへコピーするケース
      • コミットの順番を入れ替えるケース
      • コミットしないけどデバッグのための変更をpatchファイルとして作成するケース
      • コミットをcherry-pickして、作業中のブランチに適用するケース
      • 任意のファイルの変更のうち一部分だけをステージングにアップしてコミットするケース
        • 1行単位でステージングする場合
        • Hunk(差分の塊)単位でステージングする場合
      • 特定のコミットを削除するケース
      • 任意のコマンドをlazygit上で叩くケース
      • rebase -iで編集モードに入らずにsquashやfixupを行う方法
      • 他のリポジトリへ切り替えるケース
  • まとめ
  • 参考資料
続きを読む

初心者でも安心!サンプルアプリで学ぶ Supabase Storage RLS

はじめに

Supabase のデータベースやストレージを初めて触った際に、「RLS」というワードを目にして、以下のような気持ちになった方もいるのではないでしょうか。

  • セキュリティの為に設定が必要だけど何を設定すれば良いかわからない
  • RLSの使い所と使うメリットがわからない
  • 最低限どんなRLSの何を設定しておけばよい?

また、Storageに関しては次のような気持ちを持つ方もいるかと思います。

  • BucketのPublic/Privateって何が違うの?
  • StorageのRLSだとどのように設定するの?
  • レコードもないのになぜRLS(Row Level Security)なの?

この記事では以下の点について解説します:

  • RLSの基本的な概念と使うメリットがわかる
  • RLSの適用範囲とSupabase Storageでアクセス制御の設定方法がわかる
  • Storageの操作に必要な主なAPIと操作に必要な権限の確認方法がわかる

この記事では、RLSについての基礎的な説明を行う準備パートとSupabase Storage でのRLSの設定方法について説明を行う実践パートの2パートで説明します。

想定読者

  • Supabase 使い始めて、Storageを使い始めようとしている方
  • RLS という用語に馴染みがない方
  • 普段フロントエンド(アプリ・Web)の開発をされている方

以下目次です。

  • はじめに
  • 想定読者
  • 準備パート
    • Supabase Storageとは?
    • RLS(Row Level Security)とは?
      • Q. なぜDBでもないのにRLSと呼ぶの?
    • RLSの適用範囲
    • Policyの設定内容
      • 項目の説明
        • 誰が(role)
        • 何を(objects)
        • どの条件で(conditions)
        • 操作の種類(CRUD)
    • Policyのバイパス(スキップ)について
    • Bucketのpublic と privateの違い
  • 実践パート
    • 事前準備
    • Supabase Storage でのPolicyの設定手順
    • ステップアップ
    • 日々の開発で活用できるコマンド
    • ローカル環境のStorageのPolicyをsqlファイルとして出力する
    • ローカル環境のStorageのbucketの設定を storage_dump.sql という sqlファイルに出力する
    • ローカルの dump.sqlという sqlファイルを自身のローカル環境へ反映
  • 雑感
  • 参考サイト
続きを読む

【Supabase CLI】ローカルとリモートの両方を変更し、Supabase CLIの`supabase db pull`が失敗した時に行った対応内容【supabase migration repair】

こんにちは。 pregum_foxです。 また技術書典などのイベントが近づいているので、目当ての本を探しつつ最近の楽しみにしています。

今回はSupabase CLIを使って、ローカル環境をリモートからpullしようとsupabase db pull コマンドを叩いた時にエラーが出た時の対処法について記載していきます。

問題概要

開発で使用しているローカル環境のSupabaseプロジェクトのDBを変更した後、リモート環境で別の変更を加えた後にsupabase db pullを叩いた時にエラーが出ました。

エラー画面

原因

ローカル環境とリモート環境のマイグレーションの同期が取れていないことが原因でした。

対応内容

上記の問題を解消するために対応内容について記載します。

前提条件

まずは前提として以下の項目を満たしていることを確認します。

  • [x] Dockerが起動していること
    • Dockerが起動していないとsupabase コマンドが動作しませんでした
  • [x] supabase login コマンドでログインできていること
  • [x] supabase linkコマンドでpullしたい対象のプロジェクトへリンクできていること
  • [x] supabase statusコマンドでローカル環境のSupabaseプロジェクトの情報が表示されること
    • こちらはもしかすると不要かもです

エラー内容と対処法

  1. マイグレーションの状態確認
    supabase migration listコマンドでマイグレーションファイルの状態を確認しました。

片方のみに反映されているマイグレーションファイルは見当たらなかったので、もう少し調べました。

その結果、リモート側の変更がローカルにすでにその変更が含まれているためにエラーが出ていることがわかりました。(スクショ時にはすでにマイグレーションファイルを削除した後だったので、後付けしております)

  1. ローカル側の変更を削除
    ローカルとリモートの差異を解消するため、ローカル環境にある不要なマイグレーションファイルを削除しました。

    例として、20240917140424_~マイグレーションファイルを削除しました。

マイグレーションファイルを削除

この時点でsupabase migration list を叩くと以下のようにローカル環境の欄が空になっていることが確認できます。

  1. リモートを適用前にマーク
    削除後、supabase migration repair --status reverted <マイグレーション日付>コマンドを使って、リモートの最新マイグレーションを適用前にマークしました。

ここでは、supabase migration repiar --status reverted 20240917140424 というコマンドを叩きました。

このコマンドにより、supabase migration listの結果からも該当マイグレーションが消えることが確認できました。

  1. リモートデータを再取得
    上記の設定後にsupabase db pullを再実行し、リモートデータの取得が正常に完了しました。

この際、「remote_schema」マイグレーションファイルを保存するかどうか尋ねられるため、保存する選択を行いました。

上記で保存しなくともリモート環境には保存されている為、特別な理由がない限りは保存する選択をおすすめします。

リモート環境のマイグレーション履歴はSupabaseのDatabase > PLATFORM > Migrations から確認できます。

リモート環境のマイグレーション履歴の参照場所

上記で無事リモート環境とローカル環境のマイグレーションが同期され、supabase db pullが動作するようになりました。 お疲れ様でした。

雑感

開発時はGUIでぽちぽちできるのですごい楽なのですが、いざローカル環境を整えて開発しようとするとよくDB関連の問題に遭遇し、その度に時間を浪費することがあったので、頻発するdb pullについてのエラー対処法を備忘録として残しました。 他にもマイグレーション方法などローカル環境で作成したfunctionをリモート環境へpushする方法など記事をそのうちまとめたいなと考えています。 ここまで読んでいただきありがとうございました。

参考サイト

https://supabase.com/docs/reference/cli/supabase-migration-repair

【Keyball】Keyball61の組み立て時に知っておきたかったメモ

こんにちは。pregum_foxです。

今回は、初めて自作キーボードを購入しましたので、組み立てる際に知っておきたかったこと、組み立てた後に知っておくと良いメモを書いていきます。

読むとわかること

  • Keyball61をキーボードとして使用する為に必要なもの
  • Keyball61の組み立て時間のサンプル

想定読者

  • Keyball61を購入しようか迷っている自作キーボード初心者の方
  • 結局Keyball61をキーボードとして使うにはが必要?と思っている方
  • キースイッチとは?ProMicroとは?TRRSケーブル?という方

以下目次です。

  • 読むとわかること
  • 想定読者
  • 記事を書いている人間のKeyball歴と普段使うキー配列
  • 組み立てた範囲と組み立てにかかった時間
    • 組み立てた範囲
    • 組み立てにかかった時間
  • 備忘録: Keyballの組み立て前に知っておきたいこと
    • 商品の購入に利用したサイト
    • キーボードとして使うためにいくつかの部品の購入
    • ダイオードとソケットの半田付け
    • 精密ピンセットとルーペの必要性
    • ネジやダイオードを一時的に入れておく容器があると良かった
  • 組み立てた後に知っておきたいこと
    • キーマップの設定
    • マウスとスクロールの感度設定
    • Layerの存在
    • キー配置の注意点
    • 接触不良の確認
    • 通常は有線のみ操作可能
    • まとめ
続きを読む

【Drift】Driftの個人的なTipsをまとめてみた【Flutter】

こんにちは。pregum_foxです。

今回はdriftの使い方についていくつか自分が調べて情報がなかった箇所についてtipsとして書いていこうと思います。

以下目次です。

  • 検証環境
  • サンプルで作成したリポジトリ
  • set up
  • primaryKeyをuuidにする方法
  • 外部キーの有効化
  • 外部キー制約の定義方法(CASCADE / RESTRICT 等)
  • 中間テーブルを含むDB操作
  • マイグレーション方法
  • serializer(DataTimeをISO8601形式にする)
  • toJsonで出力されるMapのkeyをキャメルケースからスネークケースに変える
  • drift_db_viewerの使い方
  • シンプルなCRUD操作で使用できるmanagers
  • postgreSQL のクライアントとしてDriftを使用する
  • まとめ
続きを読む