Volt Introduction and Docs

Store コレクション

ストアコレクションは、データベースにデータを保存するためのものです。現在サポートされているデータベースは Mongo のみです。(他のものも検討中です。おそらく次は RethinkDB と Postgres に対応するでしょう)store は、サーバーからデータが帰ってくるのを待つ必要があります。したがって、store に対するクエリメソッドはすべて promise を返すようになっています。もし promise について知らないのであれば、続きを読む前に Opal の promise に関するドキュメントを一読してください

Volt ではフロントエンドとバックエンドのどちらでも store にアクセスすることができます。そして、ブラウザとサーバー間でデータが自動的に同期されます。store のデータに対する変更はすべて、そのデータを利用中のすべてのクライアントに対して反映されます。(ただし、後述の buffer が使われている場合は除きます。)

store._items.create({name: 'Item 1'})
# => #<Promise(70297824266280): #<Volt::Model id: "9a46..5dd7", name: "Item 1">>

store._items[0]
# => #<Promise(70297821413860): #<Volt::Model id: "9a46..5dd7", name: "Item 1">>

create (もしくはappend<<) を store._items に対して実行すると、データストアに items テーブルが (まだ存在していなかった場合は) 作成され、モデルのドキュメントが挿入されますその際、グローバルにユニークな id が自動的に生成されます。

store における promise

非同期の読み込みを実現するために、store の ArrayModel に対するメソッド実行は promise を返します。そのクエリの結果を処理する場合は .then を使います。

store._items.first.then do |item|
  # item に対する処理
end

ruby/opal のpromiseについてはこのページを参照してください

バインディングにおけるpromise

promiseはバインディングに渡され、promiseが解決されると値を更新します。これは、以下のようなことが可能であることを意味します。

{{ store._items.first.then {|i| i._name } }}

これは最初の要素を取得し、それが解決したらその名前を返しています。これはリアクティブ性を保つためでもあります。なぜなら、もし最初の要素が変わった場合、バインディングを再度実行して再度解決するからです。

Promise メソッドフォワーディング

上記の例をよりシンプルにするために、Volt は promise を拡張し、promise に対してのメソッドの直接実行を可能にし、promise が解決した場合にそのメソッドが解決された値に対して実行されるようにしています。したがって、意味的に以下は同じになります。

store._items.first.then {|i| i._name }
store._items.first._name

Promise メソッドフォワーディングは、Promise クラスに定義されていないメソッドに対してのみ有効です。 現在のところ、以下のメソッドはすでに Promise クラスに定義されています。(以下のうち多くのものを削除するために、Promise クラスの再実装が計画されています) 。

error、 prev、 next、 value、 act?、 action、 exception?、 realized?、 resolved?、 rejected?、 ^、 <<、 >>、 resolve、 resolve!、 reject、 reject!、 exception!、 then、 do、 fail、 rescue、 catch、 always、 finally、 ensure、 trace、 inspect、 method_missing、 each、 value_or_error、 to_json、 unwrap、 sync

おそらく、実際にこれが影響するのは .to_json や .inspect に関してでしょう。

promise の同期

もし store が (例えば tasks などで) サーバー側のみである場合、promise に対して .sync を実行することで、同期的に解決しその結果を返すことができます。もし promise が失敗した場合、.sync はエラーを発生させます。

# これはサーバー、もしくはコンソール上でのみ有効です

store._items.create({name: 'Item 1'})

# .sync blocks until the items are loaded
store._items.first.sync
# => #<Volt::Model id: "3607..a0b0", name: "Item 1">

store._items.size.sync
# => 1

クエリ

現在、store は MongoDB のデータベースに永続化されます。データストアを問わないサポートを実現できるようにデータプロバイダ API を開発中です。現在、Volt がサポートするクエリメソッドは以下の通りです。

.where

.where は引数を MongoDB に渡し、.find を実行します。

.limit

.limit は必要に応じて結果の数を制限します。

.skip

.skip はどこから取得を開始するかを設定しますstore._items.skip(5).limit(10) は 5から15番目の要素を取得します。

.order

.order は引数を MongoDB に渡し、.sort を呼び出します。.sort はすでに Ruby の Enum クラスで定義されているため、代わりに .order をメソッド名として使っています。

モデルの状態の保存

サーバーとのデータの同期にはどうしても遅延があります。そこで、モデルが読み込み状態であるかを判断するための loaded_state というメソッドをストアモデルは提供します。

状態 説明
not_loaded データは読み込まれていません
loading モデルはサーバーからデータを取得中です
loaded データは読み込まれており、未同期のデータはありません
dirty データは読み込まれていますが、サーバーと同期されていません