RailsのDraperを使用してトッピング機能を実装してみた
今回は、Rails で Draper を使用して Decorator を実装してみた。
今回やりたいこと
前回、RubyでGoFのDecoratorパターンを勉強したので、今回はRailsでも実装してみたいと思う。
※とりあえず、前の記事(Rubyで書くDecoratorパターン - たくあんポリポリ)で書いたのと同じで、アイスにカシューナッツをトッピングできるものを目指す。
実装
Helper版
Controller
class IcesController < ApplicationController def show @ice = Ice.find(params[:id]) end end
View
<h1>Ices#show</h1> <p><%= topping(@ice) %></p>
Helper
module IcesHelper def topping(ice) "CashewNuts #{ice.name} Icecream" end end
Result
Draper版
Controller
class IcesController < ApplicationController def show @ice = Ice.find(params[:id]).decorate end end
View
<h1>Ices#show</h1> <p><%= @ice.topping %></p>
Decorator
class IceDecorator < Draper::Decorator delegate_all def topping "CashewNuts #{ice.name} Icecream" end end
Result
Helper版とDraper版
app/helper 以下に書かれたメソッドは全てのViewから読み出すことが可能。つまり、Helperを使用する限り、別のhelperに同じtoppingという名前のメソッドが存在してしまうとメソッド名が競合してしまい、表示が思った通りにいかない可能性がある。そういった状態にならないようにするためには、アイスの他にクレープのtopppingメソッドがほしかった場合は以下のように書く必要がでてくる。
アイスの場合
def ice_topping "CashewNuts #{ice.name} Icecream" end
topppingの前に"ice_"をつけている。
クレープの場合
def crepe_topping "Strawberry #{crepe.name} Crepe" end
topppingの前に"crepe_"をつけている。
しかし、どうもiceやcrepeがたくさん出てきていて気持ち悪い。そのような場合にDraper版を使用する。これは、アイスやクレープのオブジェクトを、Decoratorオブジェクト化してインスタンス変数に格納する。Viewでインスタンス変数を使用して、クラス内に書かれているtoppingメソッドを実行する。つまり、同じメソッド名でかいてもお互いに影響しあわない。そうなるとtopping前の"ice""crepe"は削除できる。(これできれいになりました。)
結局、どんな時につかうの?
いろいろなところで言われているが、Viewに表示する内容をちょこっとだけ装飾したいとき。今回はIcecreamの前にCashewNutsをつけた。
あと、helperが混沌としてきて、名前の競合とかが怖くなってきたらDraperで整理できるとよいかな。