48
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Supabaseストレージに画像をアップロードし、表示する

Last updated at Posted at 2022-12-25

どうも、SupabaseでDevRelをしているタイラーです。

意外とちゃんとSupabaseストレージの使い方を日本語で説明している記事がなく、download()を使ったりした少し回りくどい実装をしているケースを見かけたりしたので、今日はシンプルにSupabaseストレージに画像をアップロードしてその画像を表示するやり方を紹介します。

アップロード

アップロードはシンプルにstorage.upload()メソッドを呼ぶだけでできます。下記はReactを使った簡単な例です。type="file"inputエレメントを用意して、そのエレメントに対して選択されている画像が変更されたときにhandleImageChange()メソッドが呼ばれ画像がアップロードされるようになっています。

  const handleImageChange = async (
    event: ChangeEvent<HTMLInputElement>
  ): Promise<void> => {
    if (!event.target.files || event.target.files.length == 0) {
      // 画像が選択されていないのでreturn
      return
    }

    const file = event.target.files[0] // 選択された画像を取得
    const filePath = `my_folder/${file.name}` // 画像の保存先のpathを指定
    const { error } = await supabase.storage
      .from('my_bucket')
      .upload(filePath, file)
    if (error) {
      // ここでエラーハンドリング
    }
  }
  ...
  <input type="file" onChange={handleImageChange} />

ここではfilePathという変数でファイルを指定バケットのどこのパスに保存するかを指定する形になっています。filePathは他にもこのようにユーザーのユーザーIDを使った方法などが主流かもしれません。

const user = await supabase.auth.getUser() // ログイン中のユーザーのユーザーオブジェクトを取得
const filePath = `${user.id}/${file.name}` // ユーザーIDのフォルダの中にファイルを保存

ここではReactとTypescriptを使った例を紹介しましたが、Flutterなど他のフレームワークでも同じようなメソッドがあるのでほぼ同じ感じで実装できます。

画像の表示

画像の表示はとてもシンプルです。Webであろうがモバイルアプリであろうが画像はその画像のURLさえ取得できてしまえば表示できるのでURLを取得しましょう。URLの取得の仕方は2種類あります。

エラーハンドリングは省略しますが、

// publicなバケットに画像が保存されている場合
const { data } =  supabase.storage.from('my_bucket').getPublicUrl(filePath)
const imageUrl = data.publicUrl

// privateなバケットに画像が保存されている場合
const {data, error} = await supabase.storage.from('my_bucket').createSignedUrl(filePath, 600)
const imageUrl = data.signedUrl

これだけでimageUrl変数に画像のURLが格納されます。あとはこれをウェブであれば<img />srcに指定するだけだし、FlutterであればImage.networkウィジェットに渡してあげるだけです。

あと、よくあるのは画像をアップロードした際にその画像のURLを取得してしまって、そのURLをデータベースに保存してしまう手法です。個人的に何かアプリを作るときはこのやり方をいつも使っています。

  const handleImageChange = async (
    event: ChangeEvent<HTMLInputElement>
  ): Promise<void> => {
    if (!event.target.files || event.target.files.length == 0) {
      // 画像が選択されていないのでreturn
      return
    }

    const file = event.target.files[0] // 選択された画像を取得
    const filePath = `my_folder/${file.name}` // 画像の保存先のpathを指定
    const { error } = await supabase.storage
      .from('my_bucket')
      .upload(filePath, file)
    if (error) {
      // ここでエラーハンドリング
    }
    
    // 画像のURLを取得
    const { data } = supabase.storage.from('my_bucket').getPublicUrl(filePath)
    const imageUrl = data.publicUrl
    
    // 画像のURLをDBに保存
    const { error: databaseError } = await supabase
      .from('my_table')
      .insert({ imageUrl: imageUrl })
  }

DBに保存する部分のコードは実際にはユースケースによって変わってくると思うのですが、例えばこの画像アップロードがプロフィール画像を変更するような処理なのであればprofilesテーブルに対してupdateするような処理になるでしょうし、何か画像つきの投稿をするようなアプリなのであればpostsテーブルに対して投稿文などの他のデータと一緒にinsertするような処理になるのかなと思います。

このようにDBに画像のURLを挿入してあげることで今度そのDBからデータをロードした際にはsupabase.storage系のメソッドを呼ぶことなく直接そのURlを<img />などに渡してあげることで表示することができ、実装が楽になります。

以上、少しでもみなさんのSupabaseストレージの理解を深めるお手伝いができたら光栄です。

48
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
48
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?