Nuxt.jsプロジェクトでFirebase Storageに画像ファイルをアップロードする

はじめに

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

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

GitHub - whitia/nuxt-firebase-sample

前回まではFirestoreを利用して名前や年齡といったテキストベースのデータ永続化などを行いました。

今回はFirebase Storageを利用して画像を保存したいと思います。これまでユーザー情報について扱ってきたので、各ユーザーにアバターを設定できるようにしていきます。

概念図

(1) uploadImageアクションでFirebase Storageに画像を保存します。

(2) (1)の戻り値で保存した画像のURLが返されます。

(3) (2)のURLをaddUserアクションに渡します。

(4) ユーザー情報のimageフィールドに画像のURLを保存します。

準備

事前にFirebase Storageのバケットを作成しておいてください。また、作成したバケットのセキュリティルールを以下のページを参考にして行ってください。

Storage セキュリティ ルールを使ってみる  |  Firebase

実装

pages/users/create.vueに以下を修正/追記します。

<template>
  <!-- 以下を修正 -->
  <b-form @submit.prevent="addUser" enctype="multipart/form-data">
    <div class="container mt-5">
      ...

      <!-- 以下を追記 -->
      <div class="row justify-content-center">
        <div class="col-12 col-sm-3">
          Image
          <b-form-file
            v-model="user.avatar"
            placeholder="画像ファイルを選択してください"
            drop-placeholder="画像ファイルをドラッグ&ドロップしてください"
            accept="image"
            id="avatar"
            class="mb-3"
            required
            plain
          ></b-form-file>
        </div>
      </div>

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

<script>
export default {
  data() {
    return {
      user: {
        name: {
          first: null,
          last: null
        },
        age: null,
        // 以下を追記
        avatar: null
      }
    }
  },
  methods: {
    addUser() {
      // 以下を修正
      this.$store.dispatch('uploadFile', {
        file: this.user.avatar
      })
      .then(response => {
        this.user.id = response.name
        this.user.avatar = response.url
        this.$store.dispatch('addUser', { user: this.user })
        .then(() => {
          setTimeout(() => {
            this.$router.push('/users')
          }, 1000)
        })
      })
    }
  }
}
</script>

ファイル選択フォームを追加しました。Bootstrap-Vueのaccept="image"というプロパティを設定することで画像ファイルのみができるようになります。

addUserメソッドを修正します。まずVuexストアのuploadFileメソッドで画像をFirebase Storageに保存し、保存した画像のURLをユーザー情報に付け足してユーザー情報を保存しています。

addUserが完了した1秒後にユーザー一覧画面に遷移します。

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

import { v4 as uuidv4 } from 'uuid';
import firebase from '~/plugins/firebase'
// 以下を追記
import 'firebase/storage'

const db = firebase.firestore()
const usersRef = db.collection('users')
// 以下を追記
const firestorage = firebase.storage()

export const state = () => ({
  users: [],
  user: {
    id: '',
    name: {
      first: '',
      last: ''
    },
    age: ''
  }
})

export const actions = {
  addUser({ commit }, payload) {
    const user = {
      // 以下を修正
      id: payload.user.id,
      name: payload.user.name,
      age: payload.user.age,
      // 以下を追記
      avatar: payload.user.avatar,
      created_at: firebase.firestore.FieldValue.serverTimestamp(),
      updated_at: firebase.firestore.FieldValue.serverTimestamp()
    }

    return new Promise((resolve, reject) => {
      usersRef.add(user)
      .then(ref => {
        resolve(true)
      })
      .catch(error => {
        console.error('An error occurred in addUser(): ', error)
        reject(error)
      })
    })
  },

  ...

  // 以下を追記
  uploadFile({ commit }, payload) {
    const name = uuidv4()

    return new Promise((resolve, reject) => {
      firestorage.ref('images/' + name).put(payload.file)
      .then(snapshot => {
        snapshot.ref.getDownloadURL()
        .then(url => {
          resolve({ name, url })
        })
      })
      .catch(error => {
        console.error('An error occurred in uploadFile(): ', error)
        reject(error)
      })
    })
  }

  ...
}

uploadFileアクションの追加と、addUserアクションにavatarフィールドの追加を行いました。

画像をFirebase Storageに保存し、そのURLをFirestoreに保存できるようになったので、最後にユーザー一覧画面に画像を表示するように修正しましょう。

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

<template>
  <div class="container mt-5">

    <div class="row justify-content-center mb-3">
      <div class="col-12 col-sm-6">
        <h2>Users</h2>
      </div>
    </div>

    <div class="row justify-content-center mb-3">
      <!-- 以下を追記 -->
      <div class="col-12 col-sm-1 font-weight-bold">Avatar</div>
      <div class="col-12 col-sm-2 font-weight-bold">Name</div>
      <div class="col-12 col-sm-1 font-weight-bold">Age</div>
      <div class="col-12 col-sm-1 font-weight-bold">Edit</div>
      <div class="col-12 col-sm-1 font-weight-bold">Delete</div>
    </div>

    <div v-for="(user, key) in $store.getters.getUsers" :key="key"
         class="row justify-content-center align-items-center mb-3">
      <!-- 以下を追記 -->
      <div class="col-12 col-sm-1">
        <img :src="user.avatar" class="img-fluid rounded-circle" />
      </div>

      ...
    </div>

  </div>
</template>

<script>
// スクリプトは変更なし
</script>

いったん3人のユーザー情報をすべて消してから画像つきで再作成します。ユーザー一覧画面は以下のようになっているでしょうか。

まとめ

Firebase Storageに画像を保存する方法を解説しました。

長くなってしまったので変更/削除する方法は次の記事でまとめたいと思います。

関連記事

【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日 16:52
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