Open4

Supabase の update で 404 が出てテーブルに存在するデータを更新できなかった

"@supabase/supabase-js": "^1.24.0"`

SELECT, DELETE は動いた

const { data, error } = await supabase
  .from('post_likes')
  .select()
  .match({ post_id: postId, account_id: accountId })
// console.log(data)
[
    {
        "postId": 1,
        "accountId": 1,
        "read": false
    }
]

しかし、update が動かない

const { data, error } = await supabase
  .from('post_likes')
  .update({
    read: true,
  })
  .match({ post_id: postId, account_id: accountId })
// console.log(data, error)
null []

PUT /rest/v1/post_likes?post_id=eq.1&account_id=eq.1 は 404 を返す

原因は RLS の policy の設定だった。

create policy "Users can update their own like."
  on comment_likes for update with check ( auth.role() = 'authenticated' );

with checkusingに変えたら動いた

create policy "Users can update their own like."
  on comment_likes for update using ( auth.role() = 'authenticated' );

usingwith checkの違いは以下

using

任意のSQL条件式(戻り値はboolean)です。(省略) 行単位セキュリティが有効なときは、テーブルへの問い合わせにこの式が追加されます。 この式がtrueを返す行が可視となります。 この式がfalseまたはnullを返す行は、ユーザには(SELECTにおいて)不可視となり、また(UPDATEあるいはDELETEでは)更新の対象ではなくなります。 そのような行は静かに無視され、エラーは報告されません。

using が true を返す行が可視になる。

using が定義されていなかったので、先ほどはエラーメッセージもなく update ができなかったのだ。

with check

任意のSQL条件式(戻り値はboolean)です。 (省略) この式は、そのテーブルに対するINSERTおよびUPDATEの問い合わせで使用され、この式の評価がtrueになる行のみが許されます。 挿入されるレコード、あるいは更新の結果のレコードでこの式の評価がfalseまたはnullになるものについては、エラーが発生します。 check_expressionは元の内容ではなく、予定される更新の後の新しい内容に対して評価されることに注意してください。

with check が true を返す行が挿入・更新可能となる。

with check は INSERTUPDATEで使用され、挿入・更新予定の内容を評価する。
つまり、新しい行のデータを使って条件文を組み立てられるということだ

出典

https://www.postgresql.jp/document/9.6/html/sql-createpolicy.html

なお、UPDATEに関しては以下のルールが適用される

USING句だけが指定されていた場合は、それがUSINGとWITH CHECKの両方に対して使用されます。

ログインするとコメントできます