Nuxt.jsプロジェクトでFirebase Storageにアップロードした画像を変更/削除する

はじめに

数回に分けてNuxt.jsプロジェクトでデータの永続化を行う方法を解説しています。これらの記事は上から順番に読んでいくことを想定しています。

これらの記事で作成したNuxt.jsプロジェクトは以下のGitHubリポジトリーで公開しています。

GitHub - whitia/nuxt-firebase-sample

前回はユーザーごとに画像ファイルをつけられるようにしました。その画像ファイルはFirebase Storageに保存しました。今回はその続きで、Firebase Storageに保存した画像ファイルを変更/削除する方法について解説します。

実装

諸事情により、まずは画像ファイルを削除する処理を作っていきます。

pages/users/index.vueに以下を追記します。

<!-- テンプレートは変更なし -->

export default {
  ...

  methods: {
    deleteUser(id) {
      if (!confirm('Are you sure?')) return

      this.$store.dispatch('deleteUser', { id })
      .then(() => {
        setTimeout(() => {
          this.$store.dispatch('fetchUsers')
        }, 1000)
      })

      // 以下を追記
      this.$store.dispatch('deleteFile', { name: id })
    }
  }
}

ユーザー情報を削除した後、画像ファイルを削除するためにVuexストアのdeleteFileアクションを呼び出します。

store/index.jsに以下を追記します。

...

export const actions = {
  ...

  // 以下を追記
  deleteFile({ commit }, payload) {
    return new Promise((resolve, reject) => {
      firestorage.ref('images/').child(payload.name).delete()
      .then(() => {
        resolve(true)
      })
      .catch(error => {
        console.log('An error occurred in deleteFile(): ', error)
        reject(error)
      })
    })
  }
}

...
}

deleteFileアクションはFirebase Storageの画像ファイルを削除する処理ですね。

削除処理はこれで実装完了です。ユーザー一覧画面からユーザーを削除したときに、画像ファイルも一緒に削除されているか確認してみてください。

続いて変更処理です。と言っても、Firebase Storageに保存したファイルを変更する手段はありません。ですので、通常は削除→新規という流れで処理を書いていきます。

pages/users/edit/_id.vueに以下を追記します。

<template>
  <b-form @submit.prevent="editUser">
    <div class="container mt-5">
      ...

      <!-- 以下を追記 -->
      <div class="row justify-content-center">
        <div class="col-12 col-sm-3">
          Avatar
          <b-form-file
            placeholder="画像ファイルを選択してください"
            drop-placeholder="画像ファイルをドラッグ&ドロップしてください"
            accept="image"
            id="avatar"
            class="mb-3"
            required
            plain
          ></b-form-file>
          <img :src="$store.getters.getUser.avatar" class="img-fluid rounded-circle" />
        </div>
      </div>

      ...
    </div>
  </b-form>
</template>

export default {
  ...

  methods: {
    editUser(e) {
      const user = {
        // 以下を修正
        oldId: this.$store.getters.getUser.id,
        newId: this.$store.getters.getUser.id,
        name: {
          first: e.target.first.value,
          last: e.target.last.value
        },
        age: e.target.age.value,
        // 以下を追記
        avatar: e.target.avatar.files[0]
      }

      // 以下を修正
      if (user.avatar) {
        this.$store.dispatch('deleteFile', { name: user.oldId })

        this.$store.dispatch('uploadFile', {
          file: user.avatar
        })
        .then(response => {
          user.newId = response.name
          user.avatar = response.url
          this.$store.dispatch('editUser', { user })
          .then(() => {
            setTimeout(() => {
              this.$router.push('/users')
            }, 1000)
          })
        })
      } else {
        user.avatar = this.$store.getters.getUser.avatar
        this.$store.dispatch('editUser', { user })
        .then(() => {
          setTimeout(() => {
            this.$router.push('/users')
          }, 1000)
        })
      }
    }
  }
}

まず前提として、ファイル選択フォームはセキュリティリスクがあるためデータをバインドすることができません。ですので、初期状態は必ず未選択状態になっています。editUserメソッドではuser.avatarが選択されているか判定しています。ファイルが選択されていれば現在の画像を削除→新しい画像を保存し、選択されていなければユーザー情報のみを更新しています。

呼び出すアクションはすでに実装済みのアクションなので追加はありません。しかし、editUserアクションを少しだけ修正する必要があります。store/index.jsを修正します。

...

export const actions = {
  ...

  editUser({ commit }, payload) {
    return new Promise((resolve, reject) => {
      // 以下を修正
      usersRef.where('id', '==', payload.user.oldId).get()
      .then(snapshot => {
        snapshot.forEach(doc => {
          const user = {
            // 以下を修正
            id: payload.user.newId,
            name: payload.user.name,
            age: payload.user.age,
            // 以下を追記
            avatar: payload.user.avatar,
            updated_at: firebase.firestore.FieldValue.serverTimestamp()
          }

          usersRef.doc(doc.id).update(user)
          .then(ref => {
            resolve(true)
          })
          .catch(error => {
            console.error('An error occurred in editUser(): ', error)
            resolve(error)
          })
        })
      })
    })
  },

  ...
}

...

画像ファイルが新しくなった場合はユーザー情報のidも更新します。しかし実装してから思いましたが、一度作成したデータのidを後から変更するのは設計思想的にあまりよろしくない気がします。本筋とは離れるので今回は気にしないことにします。

テストサーバーを起動し、ブラウザで動作を確認してみてください。ユーザーの画像を変更した場合、古い画像が削除され、新しい画像に差し替わっているでしょうか。

まとめ

Firebase Storageにアップロードした画像の変更/削除について解説しました。

Firebase Storageを使ってみた感想として、レスポンスが遅い気がしました。Firebase Storageがというより、Firebase全体が。Firebaseは近々Google Cloud Platformと統合されるという噂があります。GCPのほうが多機能でレスポンスも早いので、あえてFirebaseを使う必要はあまりないかもしれませんね...

関連記事

【Nuxt.js+Firebase】core-js関連のエラーが大量に出力される事象の原因と対処
# はじめに Nuxt.jsプロジェクトでFirebaseを使っていると、テストサーバー起動時やデプロイ時にcore-js関連のエラーが大量に出力されることがあります。 なぜエラーが出力されるのか、どうすれば解消できるのかをまとめました。 [...]
2020年6月9日 10:30
【Nuxt.js】GitHubからセキュリティアラートが届いたときの対応【package.json】
# はじめに GitHubでソース管理を行っているプロジェクトに`package.json`のセキュリティアラートが届いたときの対応を記載します。 今回はNuxt.jsで作成したプロジェクトでの対応記録のため、タイトルなどに「Nuxt.js [...]
2020年6月8日 18:01
【カテゴリ別】Nuxt.js関連の記事まとめ
# はじめに Nuxt.js関連の記事が増えてきたので、この記事でカテゴリ別にまとめたいと思います。 # 最初の一歩 - [Nuxt\.jsプロジェクトの作成から動作確認までの手順](https://www.autovice.jp/art [...]
2020年3月17日 10:40
Nuxt.jsプロジェクトでFirebase AuthenticationのGoogle認証でログインし、認証情報をLocal Storageに保存する
# はじめに この記事ではFirebase AuthenticationのGoogle認証を利用してログイン機能を作成し、そのログイン情報をブラウザのLocal Storageに保存する方法を解説します。 この記事で作成したNuxt.jsプ [...]
2020年3月17日 10:21
Nuxt.jsプロジェクトでFirebase Storageに画像ファイルをアップロードする
# はじめに 数回に分けてNuxt.jsプロジェクトでデータの永続化を行う方法を解説しています。これらの記事は上から順番に読んでいくことを想定しています。 - [Nuxt\.jsプロジェクトでFirestoreを利用したデータの永続化/取り [...]
2020年3月16日 15:06
Nuxt.jsプロジェクトでFirestoreのデータを変更/削除する
# はじめに 数回に分けてNuxt.jsプロジェクトでデータの永続化を行う方法を解説しています。これらの記事は上から順番に読んでいくことを想定しています。 - [Nuxt\.jsプロジェクトでFirestoreを利用したデータの永続化/取り [...]
2020年3月16日 1:18
Nuxt.jsプロジェクトでいろいろな条件を指定してFirestoreからデータを取得する
# はじめに 数回に分けてNuxt.jsプロジェクトでデータの永続化を行う方法を解説しています。これらの記事は上から順番に読んでいくことを想定しています。 - [Nuxt\.jsプロジェクトでFirestoreを利用したデータの永続化/取り [...]
2020年3月15日 18:40
Nuxt.jsプロジェクトでFirestoreを利用したデータの永続化/取り出しの実装方法
# はじめに 数回に分けてNuxt.jsプロジェクトでデータの永続化を行う方法を解説しています。これらの記事は上から順番に読んでいくことを想定しています。 - Nuxt\.jsプロジェクトでFirestoreを利用したデータの永続化/取り出 [...]
2020年3月15日 14:04