2018-02-10
draperを使ってみた
draper というデコレーター(またはプレゼンター)の機能を持つGemを使ってみた記録。
draperとは
- draper is ...
- ViewModel for Rails
- Railsアプリケーションにオブジェクト指向なプレゼンテーション層を追加する
- Modelにメンテナンス性の高いプレゼンテーションロジックを包み込む
なぜdraperを使うのか
- Viewにまつわるロジックの置き場としてHelperも存在する。しかし、Helperはグローバルスコープを持っているため全てのControllerとViewで利用できてしまう
- Helperを使った場合、Modelに応じた微妙な差異を吸収するために新しいメソッドが追加される
- 例:Articleモデルは日時を
YYYY-MM-DD HH:mm:ss
で表現したいが、BookモデルはYYYY-MM-DD
で表現したい
- 例:Articleモデルは日時を
- Helperはオブジェクト指向に書きづらい
→ draperはこのような問題を解決する
使ってみる
セットアップ
gem 'draper'
をGemfileに追記してインストールしたら、ジェネレートコマンドを使って一式生成する。
Userモデルがあるとして、それに対応するdecoratorを生成する。
>> bin/rails g decorator User
create app/decorators/user_decorator.rb
invoke test_unit
create test/decorators/user_decorator_test.rb
app以下にdecoratorsディレクトリが作成され、その下にuser_decorator.rbが追加された。
デコレートメソッドを追加する
早速Userモデルをデコレートしていく。
ここでは、Userが自己紹介をするためのデコレートメソッドを追加した。
# app/decorators/user_decorator.rb
def greeting
"Hi! My name is #{user.name}. I am #{user.age} years old. Thank you."
end
decoratorクラス内で、対応するモデルにアクセスするには object
か 対応するモデル名(Userモデルの場合は user
)を呼び出す。
Controllerでモデルをデコレートする
Modelをデコレートする準備は整ったので、次はControllerで取得したModelをデコレートした上でViewに受け渡す。
次のように、Modelに対して decorate
メソッドを呼び出すだけでOK。
# app/controllers/users_controller.rb
def show
@user = User.find_by(id: params[:id]).decorate
end
Viewでデコレートメソッドを呼び出す
Viewではデコレートされていることを意識する必要はなく、普通にメソッドを呼び出すだけでいい。
<!-- app/views/users/show.html.erb -->
<h1><%= @user.greeting %></h1>
画面
これでdraperを使った一連の実装を体感できた。
アソシエーションに対応する
関連するモデルも含めてデコレートしたい場合は、次のようにデコレータクラスで decorates_association
メソッドを呼び出す。
# app/decorators/user_decorator.rb
class UserDecorator < Draper::Decorator
# ここでは、UserはN個のDeckを持つ関連が設定されているとする
decorates_association :decks
end
これで、deck側もデコレートされたオブジェクトとして扱うことができる
その他のメモ
- decoratorクラス内で、helperにアクセスするには
h
を呼び出す- 例:
h.content_tag(:strong, user.name)
- 例:
- コレクションをdecorateするいくつかの方法があるようだ
UserDecorator.decorate_collection(User.all)
User.all.decorate
- これは具体的に何が違うのかまで調べていない
ApplicationDecorator
などとして、Decorator共通の処理を括りだすことができる。この場合、各デコレータクラスはDraper::Decorator
ではなくApplicationDecorator
を継承するようにするclass ApplicationDecorator < Draper::Decorator
class UserDecorator < ApplicationDecorator
- Decoratorクラスはデフォルトで
deltega_all
が呼び出され、全てのメソッド呼び出しを委譲しているが、delgate
メソッドで個別に指定することも可能 - どのデコレータを使うかの指定も可能。デフォルトではファイル名から判定されている。