こんなことがしたい(けどうまくいかない)
ブロックを受け取って h1 を出力するヘルパーと、それの使用例
def render_h1_with_block(&block)
content_tag(:h1, yield, class: 'title')
end
<%= render_h1_with_block do %>
<%= render 'fuga' %>
<% end %>
<span>I am fuga.</span>
これは失敗する。h1 の外側に _fuga.html.erbがレンダリングされてしまっている。 render_h1_with_block で yield したタイミングでレスポンスボディに render 'fuga' の結果が追加されてしまうようだ。
<span>I am fuga.</span>
<h1 class="title"></h1>
解決策: capture を使う
CaptureHelper#capture をつかって render の結果を保留すればうまくいく。
The capture method extracts part of a template as a
Stringobject. You can then use this object anywhere in your templates, layout, or helpers.
(適当な翻訳) capture メソッドはテンプレートの一部を String オブジェクトとして切り出します。そのオブジェクトはテンプレート、レイアウト、ヘルパーで利用できます。
ActionView::Helpers::CaptureHelper#capture - Ruby on Rails API Document より引用
def render_h1_with_block(&block)
content_tag(:h1, capture(&block), class: 'title')
end
公式ドキュメントに従って yield を capture(&block) に書き換えてみた。
<h1 class="title"><span>I am fuga.</span></h1>
うまくいった!