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.rbapp以下に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."
enddecoratorクラス内で、対応するモデルにアクセスするには 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
endViewでデコレートメソッドを呼び出す
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メソッドで個別に指定することも可能 - どのデコレータを使うかの指定も可能。デフォルトではファイル名から判定されている。

h3pei
フリーランスのソフトウェアエンジニア。Ruby / Rails アプリケーションの開発が得意領域。設計・実装・運用まで含めてプロダクト開発が好きです。
Questalという目標達成コミュニティサービスを開発しました。仲間と一緒に目標達成に取り組みたい方はぜひご利用ください。