酒と泪とRubyとRailsと

Ruby on Rails と Objective-C は酒の肴です!

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してセットアップ

Shell
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’を追加します。

Gemfile
1
gem 'draper'
Shell
1
bundle install

Decoratorの作成

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

Shell
1
rails generate decorator article

すると

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

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

Shell
1
2
3
4
5
# mac
sudo apachectl restart

# CentOS
sudo /etc/init.d/httpd restart
Decoratorの使い方

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

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

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

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

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

articles_controller
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メソッドを追加します。

article_decorator
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メソッドがあるとします。

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

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

article_decorator
1
2
3
def comments_count
  h.pluralize article.comments.count, "Comment"
end
show.erb.html
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 リンク先のミスを修正

おすすめの書籍