Ruby on Rails
デコレータパターン
サーチ…
備考
デコレータパターンを使用すると、ベースオブジェクトに影響を与えずに、状況に応じてオブジェクトの動作を追加または変更できます。
これは、stdlibを使用する単純なRubyやDraperのような一般的な宝石を介して達成できます。
SimpleDelegatorを使用したモデルの装飾
ほとんどのRails開発者は、テンプレート自体のモデル情報を変更することから始めます。
<h1><%= "#{ @user.first_name } #{ @user.last_name }" %></h1>
<h3>joined: <%= @user.created_at.in_time_zone(current_user.timezone).strftime("%A, %d %b %Y %l:%M %p") %></h3>
多くのデータを持つモデルの場合、これはすぐに煩雑になり、あるテンプレートから別のテンプレートにロジックをコピー・ペーストすることにつながります。
この例では、stdlibのSimpleDelegator
を使用しています。
SimpleDelegator
オブジェクトへのすべての要求は、デフォルトで親オブジェクトに渡されます。プレゼンテーションロジックで任意のメソッドをオーバーライドすることも、このビューに固有の新しいメソッドを追加することもできます。
SimpleDelegator
2つのメソッドを提供します。 __setobj__
に委任されているものを対象設定、およびする__getobj__
そのオブジェクトを取得します。
class UserDecorator < SimpleDelegator
attr_reader :view
def initialize(user, view)
__setobj__ @user
@view = view
end
# new methods can call methods on the parent implicitly
def full_name
"#{ first_name } #{ last_name }"
end
# however, if you're overriding an existing method you need
# to use __getobj__
def created_at
Time.use_zone(view.current_user.timezone) do
__getobj__.created_at.strftime("%A, %d %b %Y %l:%M %p")
end
end
end
いくつかのデコレータは、この動作をワイヤリングするために魔法に依存していますが、ページ上のオブジェクトを初期化することによってプレゼンテーションロジックがどこから来ているのかをより明確にすることができます。
<% user = UserDecorator.new(@user, self) %>
<h1><%= user.full_name %></h1>
<h3>joined: <%= user.created_at %></h3>
ビュー・オブジェクトへの参照をデコレータに渡すことで、プレゼンテーション・ロジックを組み込むことなく、ビュー・ヘルパの残りの部分にアクセスすることができます。
これで、ビューテンプレートはページにデータを挿入することのみに関心があり、はるかに明確です。
Draperを使ったモデルの装飾
Draperは、コンベンションによってモデルをデコレータと自動的にマッチングさせます。
# app/decorators/user_decorator.rb
class UserDecorator < Draper::Decorator
def full_name
"#{object.first_name} #{object.last_name}"
end
def created_at
Time.use_zone(h.current_user.timezone) do
object.created_at.strftime("%A, %d %b %Y %l:%M %p")
end
end
end
ActiveRecordオブジェクトを含む@user
変数を指定すると、 @user
で#decorate
を呼び出すことによってデコレータにアクセスしたり、固有のものにしたい場合にDraperクラスを指定してデコレータにアクセスできます。
<% user = @user.decorate %><!-- OR -->
<% user = UserDecorator.decorate(@user) %>
<h1><%= user.full_name %></h1>
<h3>joined: <%= user.created_at %></h3>