トップ «前の日記(2019-01-20) 最新 次の日記(2019-01-23)» 編集

2019-01-22 [長年日記]

_ RubyのCellsのv4以降の使い方メモ

trailblazer/cells: View components for Ruby and Rails.

主に v2 以前から使っていた人向け。なんかずーっと ViewModel という言葉に引っかかっていたんだけど、ちょっと分かったかも。

まずは基本の使い方から。

定義

class SampleCell < Cell::ViewModel
  ..
end

呼び方

micro MVC 的な呼び方
cell(:<name>[, :<model>]).(:<state>[, options])

これで Cell の中のメソッドを読んだ結果を String として(to_sして)出力できる。View の中で micro MVC として使う Cells v2 以前の render_cell() 時代の使い方のイメージ。

ただのCellオブジェクトを取得する呼び方
cell(:<name>[, :<model>])

これで文字列になる前のただの初期化済み Cell オブジェクトが取得できる。

Cellの実体は.()でcallさせると安全にto_sできるオブジェクト

Cells は定義の部分よりは呼ぶ部分の方がちょっと気持ち悪い。まずマジカルさの一つは

cell().()

という見慣れない書き方なのだが、この .() は call() の syntax sugar だった。

Ruby | 「call」メソッド の Syntax Sugar 「.()」 について - Qiita

では call はどうなっているかというと、以下のようになっている。

     def call(state=:show, *args, &block)
       content = render_state(state, *args, &block)
       content.to_s
     end

call すると render して to_s している。*1

さらに

   def to_s
     call
   end

が定義されているので、 String として評価される context ではマジカルに #show が呼ばれ、view を render して何かが出力されるという算段になっている。

これを意図して rails generator で cell を作ると、まず

def show
  render
end

だけを持つ class ができる。

ということで、「なんかいい具合に to_s するための仕組みの入っているオブジェクト」というのが Cells の実体と言ってよさそう。

一つ気をつけなきゃいけないのが、Cells は View ではなく Controller の context で実行されているということ。もう一つ、v4 以降の Cells は Rails 非依存なので、Controller を継承していない。cells-rails gem では関連 module はいろいろ include しているが、Controller を継承していることは前提にしてはいけない。

で、ViewModelとして扱うってどうよ?

Controller から View 向けのロジックを追い出すために Cells を使うとよいと「伝統的なサーバサイドWeb開発アンチパターンとその対策 - C, V編 - - あーありがち(2019-01-20)」に書いたが、Cells で本当によいのだろうか?という疑問は感じるかもしれない。むしろ PORO ( Plain Old Ruby Object ) の方がよいという意見もあるのではないかと思う。

結論から言うと PORO でもよいと思う。

ただ View 側に渡しやすい何かにするための ViewModel なはずなので、最初からそういう仕組みの用意されている Cells にしておけば自動的に置き場所も決まるし、安全に to_s されるし、独自の template を追加することもできるし、Helper も呼べるし、testability も考慮されてるし、まーだいたいよいことづくめだと思う。どうせ何らかの支援は欲しくなるはずだ。

個人的には Cell という名前だけが非常に引っかかっていて、どうしても micro MVC を用意するイメージが強いので、いっそのこと

app/cells/*_view_model.rb

みたいな名前付けで置いといて*2、呼び方も

FooViewModel.new

みたいにしておくと、呼ぶ側からは明らかに render_cell の頃のアレとは違う使い方をしている感 が出るのでよいかもしれない。

これなら micro MVC 的な Cells と ViewModel を使い分けている感じをさせつつ、使っているツールは一つに絞れる。

Tags: Ruby

*1 cells-rails ではこれをさらに html_safe している

*2 app/view_models/ でもよいが