画像削除が上手くいかない!デバックの過程をチラ見せ(恥)

画像削除が上手くいかない!デバックの過程をチラ見せ(恥)

投稿日: 2025年02月09日

学習振り返り
要約
  • Supabaseのストレージから画像が削除できない問題に直面し、デバッグ用のコードを追加して原因を探った。
  • 認証は成功していたが、ファイルリストが空で、アクセス権の問題が原因と判明し、ポリシー設定を見直す必要があった。
  • 最終的に、delete操作にはselect権限が必要であることに気づき、デバッグの課程を共有することで他の人の役に立とうとした。

はじめに

あれ?動かない。エラー吐く。なんで。わからんって禿げそうになることありますよね。

今一つそんな状況を抜け出して、私のコードにはデバック用のconsole出力であふれているので、不要なコードを消す前に誰かの役に立つかもと思って公開してみますw

起きていること

画像をsupabaseのストレージから削除したい。
ストレージから消えない。エラー吐かないけど画像消えない残ってるなんで。
私、11章で画像の処理やったのを最後に一切やってなくて。かなり久々なんです。

ストレージの画像を削除するのはカリキュラムにもなかったので試行錯誤していました。
11章やってる時に面談でぶべさんは「ゴミがたまっていくだけだから消さなくていい」って話していたのですが、容量のことがあるので私はストレージから消す処理を入れたくて格闘しました。

最終形態

画像の削除する処理を行う関数です。

import { supabase } from "./supabase";

const getFilePathFromUrl = (url: string) => {
  return url.replace(/^.+\/recipe_image\//, "");
};

export const deleteImage = async ({ imageUrl }: { imageUrl: string }) => {
  const filePath = getFilePathFromUrl(imageUrl);

  return await supabase.storage.from("recipe_image/private").remove([filePath]);
};

とりあえず出力

デバック中の最終形態

import { supabase } from "./supabase";

const getFilePathFromUrl = (url: string) => {
  return url.replace(/^.+\/recipe_image\//, "");
};

export const deleteImage = async ({ imageUrl }: { imageUrl: string }) => {
  //urlあってる??の確認
  console.log("Url:", imageUrl);

  //キャッシュが残っている云々出てきたのでとりあえずやってみる(関係なかった)
  await supabase.auth.refreshSession();

  //認証済ユーザーのみのポリシーがあるので、ちゃんと認証されてるよね?の確認
  const { data: user } = await supabase.auth.getSession();
  console.log("Auth session:", user);

  //そもそもストレージにファイル存在してるのか確認
  const { data: files, error: listError } = await supabase.storage
    .from("recipe_image")
    .list("private");
  if (listError) {
    console.error("List Error:", listError);
  } else {
    console.log("Files in private folder:", files);
  }

  const filePath = getFilePathFromUrl(imageUrl);
  
  //削除したいファイルのパスあってる?の確認
  console.log("Deleting:", filePath);

  const { data, error } = await supabase.storage
    .from("recipe_image")
    .remove([filePath]);

  //削除結果の出力
  console.log("Delete result:", data, error);
  
  // console出力しつつエラー回避のため、一旦変数に受け取ってからreturn
  // return await supabase.storage.from("recipe_image/private").remove([filePath]);
  return { data, error };
};

試した結果わかったこと

console.log("Url:", imageUrl); 

→urlには問題なし

console.log("Auth session:", user);

→認証されてるから問題なし

if (listError) {
    console.error("List Error:", listError);
  } else {
    console.log("Files in private folder:", files);
  }

→空の配列が出力される!!!!
これは問題。supabaseの管理画面見る限りprivateフォルダはちゃんと存在しているため、アクセスが出来ない可能性浮上。ポリシーが怪しい。

console.log("Deleting:", filePath);

→間違いない。ちゃんとパスになってる。ファイルの存在もsupabaseで確認できる。

console.log("Delete result:", data, error);

→削除出来てない。原因はprivateフォルダにアクセスしていないからだということがファイルの配列が出てほしいところで空配列が出力されてるのでわかる。

原因は分かった。アクセスできないのか、じゃあポリシーの問題だよね・・・

でも、deleteのポリシーは、

((bucket_id = 'recipe_image'::text) AND ((storage.foldername(name))[1] = 'private'::text) AND (auth.role() = 'authenticated'::text))

問題なさそう・・なんで・・・ここで初めて絶望しました。

結論

selectのポリシーの設定がない。これでした。削除するには必要だったらしいです。

selectしてからdeleteするんでしょうね・・
deleteと分けるの辞めてくれる??って思いました。

デバックの時に考えること

どこまで出来ているか確認することで、問題の切り分けが出来ます。
どんどんデバック用のコードを追加して、どこまで問題ないのか何が問題なのか探ります。

  • 認証の問題なのか?

  • アクセスしようとしているファイルがないのか?

  • ファイル名が違うのか?

  • urlが渡せているか?

  • 削除したいデータのurlになっているか?

全部出力して確認していった結果、ファイルの存在は確認できるのに空配列になる
→アクセス権の問題っぽいのでポリシーの設定を見直すことにしました。

deleteの問題と思っていたので権限を緩めてみたりしましたが、全然ダメだったのでdeleteのポリシーの問題でもないことが分かり、ここで初めて詰みましたw

そもそも、

supabase.storage.from("recipe_image").list("private");

これはselect権限が必要な操作のはずなのでもう少し早く気づけたなと思います💦
結構時間溶かしました。。。

おわりに

最終形態のコードに必要のないコード山のように追加していってデバックした過程を書いてみました。
普通にデバックしながら問題探して解決してというのはいつも繰り返すのですが、今回は結構ハマってコード以外の問題だったので疲れましたw

デバックの仕方ワカラナイって方の参考になれば・・!

シェア!

Threads
user
吉本茜
山口在住/二児の母/育休中
Loading...
記事一覧に戻る
Threads
0