Supabaseでの画像管理に挑戦!
投稿日: 2024年12月30日
現在、オリジナルアプリ制作の12章におりまして、Reactで独自のtodoアプリを作成中です。先ほどぶべさんからLGTMをいただいた(うれしい😭)画像管理のページを振り返り、学びを記録をします。
今回のブログは、データベース連携をすでに御存知の方には当たり前やん!の内容になるかと思います🙇♀️もし読んで、解釈が異なればご指摘ください!
私はまだまだ初学者なので、なるほど✨と思ったところです。ご了承ください🙇♀️
私には小学生の子供が2人いるのですが、学校から持って帰ってくるお手紙が毎度たくさん。2人共通のお知らせがあったり、それぞれの学年のプリントがあったりと、とても煩雑で、全然整理できておりません…
それを整理したくて、各タブでカテゴリー分けができて、その中に画像(プリント)を登録・整理していけるようなページを作りました。
デザインは以下の通りです。
このページ作成は私にとっていくつもの山場がありましたが、その中の一つである、「画像をSupabaseのデータベースに登録する方法」を記録します。
今回はフロントページメイン(page.tsx)の関数の話です。
例えば、「やることリスト」などの文字の箇条書きの場合、APIを使ってデータを送信すると、そのデータがSupabaseのテーブルに登録されます。
以下は、TodoリストのSupabaseのテーブル構造の例です。
画像の場合、このテーブルに「key」という画像名のような文字列を保存し、さらに「bucket」という場所にそのkeyで紐づけた実際の画像を保存します。つまり、実際に画像が保存されている場所は「bucket(バケット)」です。supabaseではStorage部分に保存されます。
これにより、画像のメタデータはテーブルに、実体はバケットに保存されます!
バケットは初期設定が必要で、私はブログ課題の11章を参考にしながら設定を行いました。
ぶべさん、ちゃんと書いててくださってたのに、当時ちゃんと理解できてなくてごめんね。。
今回は、ログインしたユーザーだけが画像を閲覧できるようにするため、バケットの中に「private」フォルダを作成(初期設定したら自動で作成できる)し、画像がそこに保存されるようにしています。
以下は画像をアップロード(POST)するための関数です。
①バケットに画像を保存する②APIを使ってテーブルデータを作成 の2種類の処理を行っています。
// 画像を追加
const AddImage = async (event: ChangeEvent<HTMLInputElement>) => {
try {
if (!event.target.files || event.target.files.length === 0) {
alert("画像ファイル(タブ)が選択されていません。");
throw new Error("No image file selected.");
}
const file = event.target.files[0];
const filePath = `private/${uuidv4()}`;
// ★①Supabase ストレージ(バケット)に画像をアップロード
const { data: uploadData, error: uploadError } = await supabase.storage
.from("item")
.upload(filePath, file, {
cacheControl: "3600",
upsert: false,
});
if (uploadError) {
throw new Error(`Upload error: ${uploadError.message}`);
}
setThumbnailImageKey(uploadData.path);
// ★②Supabaseに画像情報を送信
const response = await fetch(
`/api/gallery_group/${selectedTabId}/items`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: token!,
},
body: JSON.stringify({
galleryGroupId: selectedTabId,
thumbnailImageKey: uploadData.path,
}),
}
);
if (response.ok) {
await fetchGalleryItems(); // 画像のリストを再取得
toast.success("画像が正常に追加されました。", {
duration: 2100,
});
} else {
const errorData = await response.json();
throw new Error(
`API error: ${errorData.message || "Unknown error occurred"}`
);
}
} catch (error) {
alert("画像の追加に失敗しました。もう一度お試しください。");
throw error;
}
};
私は最初、「//★②Supabaseに画像情報を送信」のみ書いて、「No Buket!」というアラートを何度も発生させてしまいました。11章を読み返し、バケットの初期設定と「// ★①Supabase ストレージ(バケット)に画像をアップロード」のコードを追加することにより、無事画像の管理ができるようになりました。
この要領で、PUT(更新)やDELETE(削除)のコードも実装しました。PUTは、はじめ画像を一旦削除し、新規追加するという、めんどくさい方法で書いてましたが、ぶべさんのご指摘で一発で更新する方法に切り替えることができました。
公式HPにばっちり書いてました😶🌫️ありがとうございます🙇♀️
画像アップロードの際に重要なのが「uuid(Universally Unique Identifier)」です。これは、一意のkey(ここでは画像名のようなもの)を生成するための仕組みです。
もしこのuuidを使わなかったら、異なるユーザーが同じファイル名(例:image.png)で画像をアップロードした場合、後からアップロードされたファイルが前のファイルを上書きしてしまう可能性があり、データの不整合や予期せぬエラーを招く💦というので、絶対します!複数のユーザーが同時にアクセスするようなシステムにおいて、非常に重要でだそうです。
これも11章の課題でやったこと!と覚えていたので、設定方法等を見返してすぐできたと思います✨
このページ、ほんと苦労して作りました。私なりにちゃんと書けたと思います。
よくがんばった自分!と思います(笑)
ぶべさんはじめ、お付き合いいただいた方、本当にありがとうございました。
まだオリアプは完成ではないので、引き続き制作楽しみます!
1年の振り返りブログも書けたらいいのですが、今年は力尽きそうです笑
来年の抱負も考えたのですが、ちゃんと定まっていないかもです😶🌫️
でも、これだけは言える!
コードはずっと書き続けようと思います!