IVYXON
記事一覧に戻る
一般Tips上級🧪 Recipe

友達とだけ見たいんだけど、SupabaseのRLS、どう設定すりゃいい?

Supabase RLSで特定の友達とだけデータ共有。招待制アプリのマルチテナンシーを実現する方法を解説するで。

2026年6月1日6分で読めます

Supabaseで「友達限定」とか「招待制」のアプリ作る時って、他の人のデータが絶対に見えたらあかんやん?そんな時にめっちゃ大事なんがRLS(Row Level Security)やで。

今回は「友人の推しだけが届く」みたいな招待制アプリで、どうやってRLSを設定するか教えるわ。とりあえずコピペで動くプロンプトからどうぞ!

一番雑な投げ方

とりあえず動かしたいだけなら、これ投げてみ?

Supabaseのテーブル `foodies` に `user_id` カラムがあるとするわ。
ログインしてるユーザー(`auth.uid()`)が、友達関係にあるユーザーの `foodies` だけ見れるRLSポリシー作って。
友達関係は `friends` テーブルにあって、`user_id`と`friend_id`のカラムがあると思っといて。
自分の `foodies` も見れるようにしてな。

これだけでもSQLの骨格は出てくるはずやで。

もうちょい具体的に投げるパターン

もうちょっと細かく指定したい時は、こんな感じで投げてみてな。

1. 自分の投稿と、フォローしてる友達の投稿だけ見たい時

「うちらの投稿と、フォローしてる友達の投稿だけ見たいねん」ってパターン。

ALTER TABLE foodies ENABLE ROW LEVEL SECURITY;

CREATE POLICY "show_own_and_friends_foodies" ON foodies
FOR SELECT
USING (
  foodies.user_id = auth.uid() OR
  EXISTS (
    SELECT 1 FROM friends
    WHERE
      friends.user_id = auth.uid()
      AND friends.friend_id = foodies.user_id
  )
);

2. 友達関係そのものも、自分に関連するレコードだけ見たい時

friends テーブル自体も、自分に関連するレコードだけ見せるポリシーにしとくと安心やで。

ALTER TABLE friends ENABLE ROW LEVEL SECURITY;

CREATE POLICY "show_own_friends_relations" ON friends
FOR SELECT
USING (
  friends.user_id = auth.uid() OR
  friends.friend_id = auth.uid()
);

3. 書き込み(INSERT/UPDATE/DELETE)も制限したい時

SELECTだけじゃなくて、データを作る、更新する、消す時も制限したいやん?例えば「自分の投稿しか編集できひん」とかね。

ALTER TABLE foodies ENABLE ROW LEVEL SECURITY;

-- 自分の投稿だけ編集・削除・追加できるポリシー
CREATE POLICY "manage_own_foodies" ON foodies
FOR ALL
USING (foodies.user_id = auth.uid())
WITH CHECK (foodies.user_id = auth.uid());

FOR ALLにしとけば、SELECT以外の操作も全部このポリシーが適用されるから便利やで。 WITH CHECKは書き込み時に適用される条件や。

実践例 / 実録

うちらが作った招待制レストラン推薦アプリ「くぐる」やったら、まさに「友人の推しだけが届く」を実現するためにRLSをがっつり使ってるで。

例えば、foodiesっていうおすすめ情報が入ったテーブルと、friendsっていう友達関係を管理するテーブルがあったとするやん?

foodiesテーブルにはこんな感じで情報が入ってる。

  • id (UUID)
  • user_id (UUID, 投稿者のID)
  • place_name (text, お店の名前)
  • description (text, おすすめコメント)
  • created_at (timestamp with time zone)

friendsテーブルにはこんな感じ。

  • user_id (UUID, フォローしてる人のID)
  • friend_id (UUID, フォローされてる人のID)
  • created_at (timestamp with time zone)

この状態で「ログインしてるユーザーがフォローしてる友達のfoodiesと、自分のfoodiesだけが見える」ようにするには、さっきのポリシーがまさに効いてくるんや。

実際にSupabaseのSQLエディタで流すならこんな感じやで。

-- まず、foodiesテーブルでRLSを有効にするのを忘れんといてな!
ALTER TABLE public.foodies ENABLE ROW LEVEL SECURITY;

-- 次に、友達のfoodiesを見せるポリシーを作るで
CREATE POLICY "Allow authenticated users to view their own and friends' foodies" ON public.foodies
FOR SELECT
TO authenticated -- 認証済みユーザーに適用
USING (
  -- 自分の投稿はいつでも見えるように
  foodies.user_id = auth.uid() OR
  -- 自分がフォローしてる友達の投稿も見れるように
  EXISTS (
    SELECT 1 FROM public.friends
    WHERE
      friends.user_id = auth.uid() AND
      friends.friend_id = foodies.user_id
  )
);

-- おまけ:friendsテーブルもRLSを有効にして、自分に関連する友達関係だけ見せるポリシーも作っとくと安心やで
ALTER TABLE public.friends ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Allow authenticated users to view their own friend relations" ON public.friends
FOR SELECT
TO authenticated
USING (
  friends.user_id = auth.uid() OR
  friends.friend_id = auth.uid()
);

これでログインしてるユーザー(auth.uid()で取れるよ!)が、自分と友達のデータだけを見れるようになるんや。他の人の投稿は、どんなに頑張ってもSQLで叩いても見えへんから、セキュリティはバッチリやな。

つまずきポイント

RLS、便利やけどたまに「あれ?なんで動かんの?」ってなる時があるんよな。

1. 「RLSが有効になってへんやん!」

一番よくあるのがこれ。テーブル作ってポリシー作っただけで満足してへん?ALTER TABLE your_table_name ENABLE ROW LEVEL SECURITY; これをテーブルごとに実行せんと、ポリシーは全く意味あらへんからな!

2. 「SELECTはできるのに、INSERT/UPDATE/DELETEがエラーになる!」

RLSポリシーって、デフォルトやとFOR SELECTだけになってるんよ。だからデータを読み込む時は大丈夫やけど、新しくデータを入れたり、更新したり、消したりする時はまた別のポリシーがいることが多いで。

例えば、自分の投稿だけUPDATEできるようにしたいなら、FOR UPDATEのポリシーも作らなあかんねん。

CREATE POLICY "allow_own_update" ON public.foodies
FOR UPDATE
USING (foodies.user_id = auth.uid())
WITH CHECK (foodies.user_id = auth.uid());

FOR ALLって書けば、SELECTINSERTUPDATEDELETE全部に適用されるから、書き込み系の制限が全部同じでええならこれ使うと楽やで。

3. USINGWITH CHECKの違い、よくわからん!

  • USING: これは「どの行を見たり、触ったりできるか」を決める条件や。SELECTの時に使うのはもちろん、INSERTUPDATEDELETEの時も、対象の行を特定するために使われる。
  • WITH CHECK: これは主にINSERTUPDATEの時に「新しい行や更新後の行が、このポリシーの条件を満たしてるか」をチェックする条件や。例えば「user_idが自分のもの」っていうポリシーがあって、他人のuser_idINSERTしようとしたり、自分のuser_idを他人のものにUPDATEしようとしたりすると、WITH CHECKで弾かれるんや。USINGだけでも書き込み制限できる場合が多いけど、WITH CHECKはより安全を期すために使うイメージやな。

慣れるまでは「FOR ALLUSINGWITH CHECKを同じ条件にしといたら大体大丈夫」って覚えとくのもアリやで。これでセキュアな招待制アプリ、サクッと作っちゃってな!