Draperで驚くほどRailsコードがわかりや少なったよ! 

Draperって何?

Draperは、Model/Controller/View/Helperと異なる第4のレイヤを提供するGemです。
この第4のレイヤは、海外では「Presenter」として分類されています。(正確にもう少し細かい分類があるらしいですが割愛♪)

ruby_toolbox_screen_shot


このレイヤを作るメリットは、

  • model/viewに余計なロジックを書かなくてすむ
  • Helperのメソッドが使われている場所が不明という事態を防ぐ

日本ではPresenterレイヤでは、ActiveDecoratorというGemが有名です。ActiveDecoratorもほぼ同じことができます。

Draperの紹介

Draperの説明ならRailsCastが一番わかり易かったです(説明は日本語に翻訳されています、動画は英語です)↓

#####286 Draper - RailsCasts

1年前の記事ですので、実際に動かしてみると少しコードの中身が違いますが、骨子は同じなのでフィーリングで動かせると思います。この記事では、showテンプレートが「1050バイト、34行」=>「382バイト、16行」になったのそうで、サイズを役2/3削減できたそうです。実際使ってみるともちろんコード量も減るんですが、それ以上に「コードのわかりやすさ」を実感できます。

ActiveDecoratorと比べたときの違いは、

  • ControllerでDraper専用の宣言を追加しないといけないこと。
  • helperメソッドを使うときには、「h.」か「include Draper::LazyHelpers」といった記述が必要となこと。

ちまたでの評判

というほどぶっちぎりで褒められている感じです^^

Draperの導入紹介

ここからは、「Experimenting with Draper」を簡易的に訳してみたものです。

Experimenting_with_Draper_screen_shot_20121123

セットアップ

サンプルのGitHubプロジェクトをcloneしてセットアップ

1
2
3
4
5
Git clone Git://github.com/JumpstartLab/blogger_advanced.Git
cd blogger_advanced
bundle
Rake db:setup
Rake
Draperのインストール

Gemfileに’draper’を追加します。

1
gem 'draper'
1
bundle install

Decoratorの作成

ArticleモデルのDecoratorを作成する。

1
rails generate decorator article

すると

  • app/decorators/フォルダが作成
  • app/decorators/article_decorator.rbファイルが作成、中にはArticleDecoratorクラスがあり
  • spec/decorators/フォルダが作成
  • spec/decorators/article_decorator_spec.rbファイルが作成

サーバをリスタート。もし、Apacheを使っている場合は、次のコマンドを実行。

1
2
3
4
5
# mac
sudo apachectl restart
# CentOS
sudo /etc/init.d/httpd restart
Decoratorの使い方

articles_controllerのshowアクションを例にDecoratorを使うための変更を示します。

1
2
3
def show
@article = Article.find(params[:id])
end

Decoratorを使うために、上のコードを下のように変更します。

1
2
3
4
def show
source = Article.find(params[:id])
@article = ArticleDecorator.new(source)
end

↑か↓のどちらでもOKです。

1
2
3
def show
@article = ArticleDecorator.find(params[:id])
end

これで、article_decorator側に記述したメソッドが使えます。
このxxxDecorator.newは単数/複数(Collection)両方に対応しています。

(例) showページにcreated_atを表示

showページにcreated_atを表示するために、Decorator側にcreated_atメソッドを追加します。

1
2
3
def created_at
article.created_at.strftime("%m/%d/%y - %H:%M")
end

これで、article.created_atとするとDecorator側のメソッドが呼び出されます。

(例) Commentカウンター

show pageに以下のようなComment countメソッドがあるとします。

1
<h3><%= pluralize @article.comments.count, "Comment" %></h3>

これを次のように書きなおすことでviewの見通しがよくなります。

1
2
3
def comments_count
h.pluralize article.comments.count, "Comment"
end
1
<h3><%= @article.comments_count %><h3>

View側の記述がすっきりしたと思います。View側が複雑になるとviewのif/for文で読みづらくなりますが、それをDecoratorが解消してくれます。

おまけActiveDecoratorの紹介

Draperとほぼ同機能をもつ、ActiveDecoratorについても一緒に紹介します。
ActiveDecoratorはsapporo.rbでのプレゼンテーションがバズってました↓

####ActiveDecorator導入の話

また、上のRailsCastsのコードをactive_decoratorで書きなおした記事もあったので紹介です。

####[Rails] RailsCast #286 Draper を active_decorator で書き直してみて得たこと

実際僕も試しにActiveDecorator使った時には、ここのサイトを参考にさせていただきました。かなりわかりやすくまとまっています。

Draperと比べた時の違いは、blog.article.titleの場合に「blog」はdecorateされるが、articleはdecorateされない点だと思います。ただしこれはあくまで設計思想の違いっぽいです。

あとは余談ですが、Decorator系の使い所の難しさを指摘されている方もいます。

model の decorator の話

使いどころの難しさもあるようですが、個人的にはLet’s Try!だと思います。

補足: kaminariを使う場合

Draperとページネーターのkaminariを使う場合は、Draperがうまくkaminariのメソッドを呼び出せない場合があります。

その場合は、config/initializers/draper.rbを作成して以下を記入しておくとエラーを回避できます。

1
Draper::CollectionDecorator.delegate :current_page, :total_pages, :limit_value, :total_count

Kaminari vs Draper · Issue #401 · drapergem/draper

変更来歴

13/04/18 23:15 kaminariを使う場合の補足を追記

14/02/26 06:45リンク先のミスを修正