Volt - Isomorphic in Ruby

Isomorphic in Ruby な Framework の Volt を紹介.

Features

  • Same code runs on the client and the server
  • Automatic Data Syncing
  • Reactive Data Bindings
  • Components

Volt はClient, Server共にRubyで記述するIsomorphicReactiveなWeb Application Frameworkで上のような特徴を持つ.

  1. Getting Started
  2. Same code runs on the client and the server
  3. Automatic Data Syncing
  4. Reactive Data Bindings
  5. Components
  6. See Also

Getting Started

gem install volt
volt new sample_app
cd sample_app
bundle exec volt server

これでServerが起動する.

ファイルが変更されたときには、Voltは自動的にそのファイルをreloadし、Clientに変更をpushする.

Same code runs on the client and the server

ClientとServerをRubyでIsomorphicに書ける.

First RequestはServer Sideで実行されるが、それ以降はClient Sideで実行され、HTTP Requestが発生しない.

データはModelClassで表現され、それの同期はautomaticallyにWebSocketかそれと同等のSocket通信でなされる.

Automatic Data Syncing

ある1つのクライアント上でデータが更新されたときには、 データベース、および他のリスニング中のクライアント上でも更新が行われる.

<!-- @ app/main/views/index.html -->
<:Body>
  {{ store._memos.each_with_index do |memo, index| }}
    <div>
      <label>{{ index + 1 }}</label>
      <span>{{ memo._text }}</span>
    </div>
  {{ end }}
  <form e-submit="add_memo">
    <label>memo: </label>
    <input type="text" value="{{ page._new_text }}" />
  </form>
# @ app/main/controllers/main_controller.rb
module Main
  class MainController < Volt::ModelController
    def add_memo
      store._memos << { text: page._new_text }
      page._new_text = ''
    end
  end
end
  • Viewではeachバインディングでイテレーションができる.
  • Viewではe-{イベント名}の属性でイベントをバインドして、Controllerのメソッドを呼び出すことができる.
  • Viewでは{{}}で囲った中のRubyのCodeを実行し、その返り血をrenderできる.
    • selfはControllerのインスタンスなので{{ add_memo }}main_controller.rbadd_memoが実行される.
  • _(Underscore Accessors)によって事前に定義せずにPropertyにgetとsetができる.
  • pagePage Collectionと呼ばれるもので、一時的にデータを保存するためのもの.
  • value="{{ page._new_text }}"で双方向バインドが可能.
    • Controllerでもpage._nex_textにget, setが可能.
  • storeStore Collectionと呼ばれるもので、データベースにデータを保存するためのもの.
  • Voltは複数形の属性を自動的に空のVolt::ArrayModelに初期化する.
  • Volt::ArrayModelにハッシュを追加した場合、自動的にVoltのモデルに変換される.

これだけでmemo:のText Inputに入力してEnterすると、Memoの追加ができる.

これを複数Clientsで操作をするとリアルタイムで同期しているのが確認できる.

Reactive Data Bindings

DOM (および値が変更されたことを検知したい他のすべてのコード)に対して、 自動的に、かつ正確に変更を伝えるために、データフロー/リアクティブプログラミングを利用する.

DOMに何らかの変更があった場合に、Voltは変更が必要なノードだけを更新する.

 <!-- @ app/main/views/index.html -->
 <:Body>
   {{ store._memos.each_with_index do |memo, index| }}
     <div>
       <label>{{ index + 1 }}</label>
       <span>{{ memo._text }}</span>
     </div>
   {{ end }}
   <form e-submit="add_memo">
     <label>memo</label>
     <input type="text" value="{{ page._new_text }}" />
   </form>
+  {{ if too_much_memos }}<div>Are you crazy??</div>{{ end }}
 # @ app/main/controllers/main_controller.rb
 module Main
   class MainController < Volt::ModelController
     def add_memo
       store._memos << { text: page._new_text }
       page._new_text = ''
     end
+
+    def too_much_memos
+      store._memos.size.then do |size|
+        size > 10
+      end
+    end
   end
 end
  • storeArrayModelに対するメソッド実行はpromiseを返す.

ロジックを宣言的に記述すると、Userの操作にreactiveにDOMが更新される.

Components

  • ApplicationはComponentから成り立っている.
  • app/以下のすべてのdirectoryはComponentである.
  • ComponentはGemにすることも可能.
  • Componentの依存が可能.
  • ClientとServerでコードを共有できることによって、Full StackなComponentの提供を実現する.

Componentに分割することにより、コードを再利用可能で疎結合でテストを容易なものにする.

See Also