前置き
Udemyのコースで
自分自身も見直して勉強になったので
Firebase関連の
送信・取得をまとめていきます💫
以前も何度かやっていますが、ul
とli
でコンポーネントを分けて…
というのがなかったので、
その辺も含めて💡
作ったのはfirebaseと連携した
チャット機能(Realtime Database)と
タスク管理機能(Cloud Firestore)
2画面一緒に見れて
いちいち切り替えなくて良い
便利なアプリです🍀
今回はタスク管理機能をやります。
vuexを使用しています。
ログインユーザーで取得
getters
は全てactions
でFirebaseからgetメソッド
で取得し、mutations
で上書きです。
書き込みは簡単そうだな〜と思い
読み取りからチャレンジしてみました。
ただルールをログインユーザーのみにし
書き込みに手をつけたら
mutations以外で上書きするな!
と後から例のエラーが出たので
また調整します🌱
順序的に絶対書き込みからやるべきだった
タスクの取得
送信しているデータはこんな感じで
ルールは誰でも読み書きできる状態。
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と。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
<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
もいらないし、
セキュリティ的にも安心だからです⭕️
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<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> |
成功コード②
こちらがベストコード✨
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
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
なしで全てのリストを表示に変更
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<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> |
ログインしてもエラー。
ルールがおかしいぞと思ってみたら
公式のコレクションの名前を
そのまま使用しているからですね。
ルールはログインしたアカウント情報request.auth.uid
と
自分の送信したデータにあるuid
と一致すればOK
ということで変更
request.auth != null
!=
で一致しないかどうか、
ゲストだったら空なので一致するためfalse
ログインしていたら空じゃないのでtrue
&&
かつ、という意味
task
コレクションの
自動生成されたIDにあるuid
と一致すればOKなので変更{ uid }
はワイルドカードで{ hoge }
とか何でも良いものです。task
コレクション内の
どのドキュメントにも適応されます。
基本的な読み書きのルール
1 2 3 4 5 6 7 8 9 10 11 |
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❌
そして使っていました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
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 } }, } |
まずは取得のコードを修正
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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
以外でうんたらかんたら。
ということでこの続きをやっていきます。
まとめ
誰でも読み書きできるルールでも
テンプレートで
表示の切り替えはできました✨👏
ルール変更によるエラーは
解決していませんが、
セキュリティ面で
できるに越したことないので
続けてチャレンジしていきます!