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::Decoratorclass UserDecorator < ApplicationDecorator
- Decorator クラスはデフォルトで
deltega_allが呼び出され、全てのメソッド呼び出しを委譲しているが、delgateメソッドで個別に指定することも可能 - どのデコレータを使うかの指定も可能。デフォルトではファイル名から判定されている。