あるオブジェクトに関連するhtmlコードを生成するクラスです。
htmlの中でrubyを実行するのではなくrubyでhtmlを生成するという逆転の発想です。
雑然としたhtmlテンプレートを整理することができます。
presenterのメリット
- 雑然としたhtmlテンプレートを整理する
- 重複したhtmlコードをメソッドとして抽出することで機能追加やデバッグやリファクタリングがしやすくなる
- 色々なところでフォームの塊等を使い回すことができる
decoratorとの違い
- decoratorは値を返す、ドメイン層寄り
- presenterはhtmlを返す、ユーザーインターフェース層寄り
参考コード
presenterの大元のクラス
presenter.rb
class Presenter
attr_reader :view_context
delegate :link_to, :fa_icon, :params, :sort_link, :number_to_currency,
:time_ago_in_words, to: :view_context
def initialize(view_context)
@view_context = view_context
end
private
def markup(tag_name = nil, options = {})
root = Nokogiri::HTML::DocumentFragment.parse('')
Nokogiri::HTML::Builder.with(root) do |doc|
if tag_name
doc.send(tag_name, options) do
yield(doc)
end
else
yield(doc)
end
end
root.to_html.html_safe
end
end
presenterクラスを継承してrooms_presenterを作る
rooms_presenter.rb
class RoomsPresenter < Presenter
delegate :receive_call_logs_path, :room_path, to: :view_context
def initialize(rooms, view_context)
@rooms = rooms
super(view_context)
end
def render
markup(:table, id: 'table-id' class: 'table-class') do |m|
m.thead do
header_components(m)
end
m.tbody do
@rooms.each do
body_components(m, room)
end
end
end
end
private
def header_components(m)
"よしなに"
end
def body_components(m, room)
"よしなに"
end
end
rooms_presenterをview側でnewする
rooms/index.haml
= RoomsPresenter.new(@rooms, self).render
まとめ
Rubyでhtmlを生成するというプロセスなので、テンプレートエンジンよりRubyの良さを活かしやすい(例えば継承してコードを使いまわすとか)ですが、presenter最大のメリットはhtmlの塊に名前をつけて管理できるところだと思います。それだけでこのviewはどういう意図があるのか?
がより理解しやすくなるので。