techium

このブログは何かに追われないと頑張れない人たちが週一更新をノルマに技術情報を発信するブログです。もし何か調査して欲しい内容がありましたら、@kobashinG or @muchiki0226 までいただけますと気が向いたら調査するかもしれません。

FirebaseのRealtime Databaseでルールを試してみる

今回は、Firebase Realtime Databaseのルールについて調べてみました。
ルールを設定することで、Firebaseに保存されたデータに対して読み書きを行う上での条件を付与することができます。

ここではそのサンプルを用意して確認してみます。
基本的にはこの辺りのドキュメントを翻訳しながらの説明になります。

今回取り扱うデータ

ルールを設定する際、どのようなデータを扱うかわかっていないとデータを設定できません。できるだけ取り扱うデータ構造にルールの構造を合わせてあげるのが良いです。
今回はサンプルデータとして以下のようなデータ形式を扱います。
f:id:uentseit:20160807234305p:plain

JSONでみると以下のような感じです。

{
  "SampleData" : {
    "body" : "これはサンプルデータです。",
    "childSampleData" : {
      "childName" : "太郎",
      "grandsonSampleData" : {
        "grandsonName" : "次郎"
      },
      "hasGrandson" : true
    },
    "hasChild" : true,
    "title" : "サンプルデータ"
  }
}

ルールの設定

ルールを設定して行きます。ルールには、以下に示すような3つのタイプがあります。

ルールタイプ 概要
.read Databaseから読み取りを行う際のルール
.write Databaseから書き込みを行う際のルール
.validate データベースに登録されるデータとして正しいタイプや属性の定義

ひとまず以下のようなルールをセットしてみます。

{
  "rules": {
    ".write": "auth == null",
      "SampleData":{
        ".read":"data.child('hasChild').val() === true",
        "childSampleData":{
          ".read":"data.child('hasGrandson').val() === true",
          "grandsonSampleData":{
            
          }
        }
      }
  }
}

前述の通り、ルールの構造をデータベースの構造に合わせています。
注目は5行目と7行目で、読み取りのルールを設定しています。
5行目では要素'hasChild'の値を評価し、trueの場合はSampleDataの読み取りを許可します。
7行目も同じように、要素'hasGrandson'の値を評価し、trueの場合はchildSampleDataの読み取りを許可します。

前述の「今回取り扱うデータ」の中では、要素'hasChild'と要素'hasGrandson'がともにtrueなので、以下のようにいずれも読み取りが可能となります。
f:id:uentseit:20160808001925p:plain
f:id:uentseit:20160808002026p:plain
試しに、要素'hasChild'をfalseにしてみると...
f:id:uentseit:20160808002132p:plain
このようにSampleDataが読み取れなくなります。

※今回はルールのシミュレータを用いて動作を確認しています。Androidアプリ上でデータを読み取り方法については前回を参照。

ルール設定の影響範囲

さて、上記では2つの階層にそれぞれルールを設けていますが、設定したルールがどの階層に影響するのかを意識しておく必要があります。 例えば上記の例で要素'hasChild'の値をtrue、要素'hasGrandson'の値をfalseにした場合... f:id:uentseit:20160808002626p:plain 要素'hasGrandson'の値がfalseであるにもかかわらず'/SampleData/childSampleData'を読み取れています。これは、より上の階層のルールである「".read":"data.child('hasChild').val() === false",」がtrueであるため、その評価結果が子要素にも影響しているためです。 このように、浅い階層のルールは、より深い階層のルールをオーバーライドし、親要素へのアクセス許可が子要素にも影響することになります。

あらかじめ定義された値

Realtime Databaseにはあらかじめ定義された値があり、それらの値をルールの中で用いることができます。 今回のサンプル「".read":"data.child('hasChild').val() === true",」の中でも使用しているdataもそのうちの一つです。 また、Realtime Databaseを利用し始めた最初は以下のようなルールになっているかと思いますが、ここで利用されているauthもRealtime Databaseがあらかじめ定義している値になります。

  "rules": {
    ".read": "auth != null",
    ".write": "auth != null",
  }

このあたりは次回以降でまた試していきたいと思います。