見出し画像

【Nuxt.js】Firebase Auth × Cloud Firestore ログインアカウントの送信と取得を考える

🎈 WPでも公開中です
https://wp.me/pc9NHC-1m9

#vue #nuxt #プログラミング #エンジニア

前置き

Udemyのコースで
自分自身も見直して勉強になったので
Firebase関連の
送信・取得をまとめていきます💫
以前も何度かやっていますが、
ulとliでコンポーネントを分けて…
というのがなかったので、
その辺も含めて💡

作ったのはfirebaseと連携した
チャット機能(Realtime Database)と
タスク管理機能(Cloud Firestore)
2画面一緒に見れて
いちいち切り替えなくて良い
便利なアプリです🍀

今回はタスク管理機能をやります。
vuexを使用しています。


ログインユーザーで取得

gettersは全て
actionsでFirebaseから
getメソッドで取得し、
mutationsで上書きです。

書き込みは簡単そうだな〜と思い
読み取りからチャレンジしてみました。
ただルールをログインユーザーのみにし
書き込みに手をつけたら
mutations以外で上書きするな!
と後から例のエラーが出たので
また調整します🌱

順序的に絶対書き込みからやるべきだった。

##タスクの取得

送信しているデータはこんな感じで
ルールは誰でも読み書きできる状態。

画像1

###NGコード例①

まず始めに
v-showでアカウントuser.uidと
todosで送信しているuidと
一致するものだけを表示…
したかったのですが
これはNGでした❌

・そもそもv-forとv-ifの併用がNG💥
 v-showは明記されていませんが
 実際エラーだったのでNGのようです。
 v-for-と一緒に-v-if-を使うのを避ける-必須
・他の人のデータも見れてしまうので
 セキュリティ的にもNG

todosは配列にオブジェクトが入っています。
[{ task: '', uid: 'アカウント別のuid',}, {}, {}]
そのオブジェクト全ての中の
uidとする必要があります。

computedのtodosはpropsで
ListItemTaskに渡しているので
ここを直接いじることはできないな…
と思って関数を用意して
v-showを思いつきましたが、
上記の理由でNG。

普通にv-ifしてもeslintエラーなので
//eslint-disable-lineしましたが…
vue/no-use-v-if-with-v-for
やっぱりエラーが解消されず
公式見たらNGと。

<template>
 <ul class="list list-task">
   <li
     is="ListItemTask"
     v-show="user.uid === forTodo()"
     v-for="todo in todos"
     :key="todo.id"
     :todos="todo"
   ></li>
 </ul>
</template>

<script>
export default {
 computed: {
   user() {
     return this.$store.getters.user
   },
   todos() {
     return this.$store.getters['todo/todos'] //eslint-disable-line
   },
 },
 methods: {
   forTodo() {
     const todos = this.$store.getters['todo/todos']
     todos.forEach((value) => {
       return value.uid
     })
   },
 },
}
</script>

###成功コード例①

そしてこちらを参考にしました!
v-forとv-ifの併用はダメらしいんで対策した件

そもそもcomputedにfilterかければOK!
ということで書き換え。
propsのtype: Object変える必要あるかもと
気になっていましたが大丈夫でした🌟

ただ後述するコードの
.whereを使用した方が◎
filterもいらないし、
セキュリティ的にも安心だからです⭕️

<template>
 <ul class="list list-task">
   <li
     is="ListItemTask"
     v-for="todo in todos"
     :key="todo.id"
     :todos="todo"
   ></li>
 </ul>
</template>

<script>
export default {
 computed: {
   user() {
     return this.$store.getters.user
   },
   todos() {
     return this.$store.getters['todo/todos'].filter((e) => {
       return e.uid === this.user.uid
     }) //eslint-disable-line
   },
 },
}
</script>

<style lang="scss" scoped>
.list-task {
}
</style>

###成功コード②

こちらがベストコード✨

export const actions = {
 async getData({ commit }) {
   try {
     const user = this.$fire.auth.currentUser
     const querySnapshot = await this.$fire.firestore
       .collection('task')
       .where('uid', '==', user.uid)
       .get()
     const todos = []
     querySnapshot.forEach((doc) => {
       const data = doc.data()
       todos.push(data)
     })
     commit('setData', todos)
   } catch (error) {
      console.log(error)
   }
 },
}


ルールを変更してみる

上記のコードで成功したものの、
「そもそもfirebaseのルールを
 書き換えた方が早いのでは?」
と思いチェック👀
ルールでユーザー情報を利用する

これはフィルターのような
データを絞る機能ではなく
実行するかしないかの
基準を設定みたいですね💡

ルールをコピペして変更し、
filterなしで全てのリストを表示に変更

<template>
 <ul class="list list-task">
   <li
     is="ListItemTask"
     v-for="todo in todos"
     :key="todo.id"
     :todos="todo"
   ></li>
 </ul>
</template>

<script>
export default {
 computed: {
   user() {
     return this.$store.getters.user
   },
   todos() {
     return this.$store.getters['todo/todos']
   },
 },
}
</script>

ログインしてもエラー。
ルールがおかしいぞと思ってみたら
公式のコレクションの名前を
そのまま使用しているからですね。

画像2

ルールはログインしたアカウント情報
request.auth.uidと
自分の送信したデータにある
uidと一致すればOK
ということで変更

request.auth != null
!=で一致しないかどうか、
ゲストだったら空なので一致するためfalse
ログインしていたら空じゃないのでtrue

&&
かつ、という意味

taskコレクションの
自動生成されたIDにある
uidと一致すればOKなので変更
{ uid }はワイルドカードで
{ hoge }とか何でも良いものです。
taskコレクション内の
どのドキュメントにも適応されます。
基本的な読み書きのルール

rules_version = '2';
service cloud.firestore {
 match /databases/{database}/documents {
   // Make sure the uid of the requesting user matches name of the user
   // document. The wildcard expression {userId} makes the userId variable
   // available in rules.
   match /task/{uid} {
     allow read, write: if request.auth != null && request.auth.uid == resource.data.uid;
   }
 }
}

しかしこれでもエラー💥
こちらをチェックすると…
データを安全にクエリする

取得する際に
getメソッドを使用しているとNG❌
そして使っていました。

export const actions = {
 async getData({ commit }) {
   try {
     const todos = []
     const querySnapshot = await this.$fire.firestore.collection('task').get()
     querySnapshot.forEach((doc) => {
       const data = doc.data()
       todos.push(data)
     })
     commit('setData', todos)
   } catch (error) {
     console.error("Error writing document: ", error) //eslint-disable-line
   }
 },
}

まずは取得のコードを修正

export const actions = {
 async getData({ commit }) {
   try {
     const user = this.$fire.auth.currentUser
     const querySnapshot = await this.$fire.firestore
       .collection('task')
       .where('uid', '==', user.uid)
       .get()
     const todos = []
     querySnapshot.forEach((doc) => {
       const data = doc.data()
       todos.push(data)
     })
     commit('setData', querySnapshot)
   } catch (error) {}
 },
}

ところがこれでもエラー💣💥
forEachいらないのか❓
と思いきや…
いるみたいです。
クエリを実行する

書き込みはできても
例のエラーが出ます。
mutations以外でうんたらかんたら。
ということでこの続きをやっていきます。


まとめ

誰でも読み書きできるルールでも
テンプレートで
表示の切り替えはできました✨👏
ルール変更によるエラーは
解決していませんが、
セキュリティ面で
できるに越したことないので
続けてチャレンジしていきます!

🎈 WPでも公開中です
https://wp.me/pc9NHC-1m9

この記事が気に入ったらサポートをしてみませんか?