【Firestore】ルールをこれから触り始める人へ

# 「Cloud Firestore」　とは
今回のテーマであるCloudFirestoreとはFirebaseにおけるNoSQLのデータベースのことを指します。iOS、Android、ウェブクライアントに対応しており、仕組みもシンプルで使い勝手の良いデータベースだと思います。

# ルールの設定
恐らく、この記事のタイトルを見て、読んでくれている方は、最近 Firestoreを使い始めた方で、「ルールってなんのこと？」だったり、「どうやって設定すれば良いの？」といったような気持ちでいるのではないでしょうか？

今回はそんな「これからルールを触り始める人」に向けて書きたいと思います。
以下に目を通していただければ、なんとなく書き始められると思います。

##  初期状態
Firebaseのルールを今まで触ってこなかった人の環境は恐らく、以下のようになっていると思います。

```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}
```
上記の状態は何もアクセスできない状態になります。
この状態でデータにアクセスすると以下のようなエラーメッセージが出ると思います。

```
Uncaught (in promise) FirebaseError: Missing or insufficient permissions.
```
この辺りのエラーが出ると大体は Firestoreルールの設定ミスであることが多いです。


# アクセスを許可

 Firestoreからデータを取れるようにしていくわけですが、基本的に設定していくのは初期状態の4行目からです。

```
    //先ほどの初期状態の4行目です。
    match /{document=**} {
      allow read, write: if false;
    }
```
以上のコードの意味は

**データの **（ワイルドカード）にアクセスする時、読み取り権限と書き込み権限を許可しません。**となっています。

要するに全てのアクセスを拒否している状態です。

allowをfalseで締めているので、初心者の方でもなんとなく分かる方もいるかもしれません。
苦手意識がある方も、そう言われてから、コードを見ると「なんだ、そんなことか。」と思えるのではないでしょうか。

基本的にはこのようなシンプルな形でルールを設定していけるのが特徴の1つです。


### ユーザごとのドキュメントへのアクセス制御
ログイン機能を使っているSNSの、ユーザごとのプロフィールページを作るとします。

データの構造としては「userProfile」というコレクションを作成し、そのコレクションにユーザごとのドキュメントを作成するとします。そのドキュメントの配下に、プロフィール写真やユーザ名等を登録していった時のルールを書いていきます。

![スクリーンショット 2020-12-04 14.29.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/529686/ceb817ce-7f88-8903-eef3-7985f269031b.png)


以下の例はプロフィールページにユーザ名を表示するため、データにアクセスする時のルール例です。

```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    
　　//基本的に書き換えるのはここから下だけ。

    // ユーザの名前（userName）にアクセスする時のルール
    match /userProfile/{userID}/userName {
      allow read: if true;
      allow write: if false;
    }
  }
}
```
先ほどと同じようにルールを翻訳すると、

**userProfile/ユーザID/ユーザ名にアクセスする時、読み取り権限は許可します。書き込み権限は許可しません。**

つまり、ユーザ名を表示はできるけど、変えることはできない状態になります。

データの構造を書き、そこにマッチするものの対応を、{　}の中に書き込んでくようなイメージです。

ちなみに、読み取り権限、書き込み権限はもっと細かく指定することもできます。

#### write
* create(新規のドキュメントへの書き込み)
* update（既存ドキュメントへの書き込み）
* delete（削除）

#### read
* get(単一ドキュメントの取得)
* list（クエリとコレクションの読み取り要求）

どちらも包括しているのが「write」と「read」になります。より細かく設定することによって誤ったアクセスを防ぐことができます。

## 自分のuserNameを編集できるルール
今、ユーザ名は誰にも書き変えられない状況ですが、そのユーザにとっては変更したくなることもありますよね。

そんな時は以下のように設定します。

```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    
　　//書き換えるのはここから下だけ。
    
    // ユーザの名前にアクセスする時のルール
    match /userProfile/{userID}/userName {
      allow read: if true;
      allow write: if request.auth.uid == userID;
    }
  }
}
```

writeの方が変わっているのが分かると思います。

「request.auth.uid」で現在のユーザIDを取得しています。
よって、 **userNameを変えようとしているユーザIDのが、アクセスしようとしているデータのユーザIDと一致するなら編集することが可能**ということになります。

ちなみに、

```
  allow write: if request.auth.uid != null;
```
こんな書き方をすると、**userIDがnullじゃないなら、書き込みを許可します**となり、ログインしているユーザにだけ書き込み権限を与えることもできます。

## ユーザ名を全角ひらがなに限定したい
ユーザ名を全角ひらがなだけにしたいとなった時、フロントで設定することもできますが、正規表現を使ってルールで決めることもできます。

```
  allow update: if request.resource.data.username.matches("^[ぁ-んー]+$") == true
```
「update」を使ってみました。よって、**usernameを更新する時は全角ひらがなだけ許可する**という状態です。


## 他のコレクションのデータを参照
ルールの中で他のコレクションのデータを使うこともできます。

```
 allow create: if get(/databases/$(database)/documents/premiumUserID/$(preUser)).data.uid == request.auth.uid;
```
**premiumUserID/preUserのユーザIDと現在アクセスしようとしているユーザのIDが一緒であれば、新規作成を許可する**となります。このように「get」を使うことでデータを持ってくることもできます。

ちなみに、「get」のあとの「/databases/$(database)/documents/」は初期設定の状態から無視している上から3行目の部分です。この例では絶対パスで値を取得しているようなイメージを持ってれもらえれば良いかと思います。


## 終わりに
以上の書き方がなんとなく分かれば、Firestorのルール設定スタートダッシュができると思います！

自分もまだまだ学ぶことは多いです。
お互い頑張りましょう！
最後まで読んでいただきありがとうございました！