Refinementsを使ったRails Presenter

Ruby2.1のRefinementsを使って、RailsのPresenter層ライブラリを作れるんじゃないかと週末にがんばってみたところ、いい感じに実装できた。

 

現状はサンプルのRailsアプリケーションで動くようになったところ。

 

https://github.com/kmdsbng/refinements_rails_presenter_test

 

動きを一言で説明すると、特定のViewのファイルでのみ、refineで定義したメソッドが生える。例えば、あるViewでのみ、modelにメソッドを生やす、ということができる。

これはRuby2.1のRefinementsの機能を使って実現してるだけなんだけど、Viewのなかでusingを呼び出すだけでは動いてくれなかったので、動くようにActionpackに手を加えてる。

 

まず、refine定義するモジュールのサンプル。

 

https://github.com/kmdsbng/refinements_rails_presenter_test/blob/master/app/models/concerns/post_show_presenter.rb

refinement module sample

 

普通にrefineを使って、Postモデルにメソッドを定義してる。これはAutoLoadされるディレクトリならどこに置いてもいい。

 

https://github.com/kmdsbng/refinements_rails_presenter_test/blob/master/app/views/posts/show.html.slim

refinemehts rails presenter sample

 

これがViewの定義。 slimで書いてる。

先頭の using と書いてる行で、refineを定義しているmoduleを指定してる。

これで、このViewではPost#body_lengthが使えるようになる。

 

usingがViewの中で使えるなら、特別な処理の必要はなかったんだけど、残念ながら using は現状トップレベルからしか呼び出せないという制限がある。

だから、Viewテンプレートをevalしてるところで、usingを加えてevalするようにモンキーパッチを当てたところ、うまくいった。

 

Draperなどの既存のRails Presenterライブラリは、 modelをラップしたりextendを使ったりして model の機能拡張を行ってる。このやり方だとmodelインスタンスすべてに処理しないといけないのでどうしても手間がかかってしまったが、Refinementsが使えるならもっとスマートに同様の機能が実現できる。かなり有望なアプローチだと思う。