Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Rails の helper でブロックを受け取って、そのブロックの中で render をつかいたい

More than 1 year has passed since last update.

こんなことがしたい(けどうまくいかない)

ブロックを受け取って h1 を出力するヘルパーと、それの使用例

hoge_helper.rb
  def render_h1_with_block(&block)
    content_tag(:h1, yield, class: 'title')
  end
hoge/index.html.erb
<%= render_h1_with_block do %>
  <%= render 'fuga' %>
<% end %>
hoge/_fuga.html.erb
  <span>I am fuga.</span>

これは失敗する。h1 の外側に _fuga.html.erbがレンダリングされてしまっている。 render_h1_with_blockyield したタイミングでレスポンスボディに render 'fuga' の結果が追加されてしまうようだ。

意図しない結果になったindex.html
<span>I am fuga.</span>
<h1 class="title"></h1>

解決策: capture を使う

CaptureHelper#capture をつかって render の結果を保留すればうまくいく。

The capture method extracts part of a template as a String object. You can then use this object anywhere in your templates, layout, or helpers.

(適当な翻訳) capture メソッドはテンプレートの一部を String オブジェクトとして切り出します。そのオブジェクトはテンプレート、レイアウト、ヘルパーで利用できます。

ActionView::Helpers::CaptureHelper#capture - Ruby on Rails API Document より引用

hoge_helper.rb
  def render_h1_with_block(&block)
    content_tag(:h1, capture(&block), class: 'title')
  end

公式ドキュメントに従って yieldcapture(&block) に書き換えてみた。

意図通りの結果になったindex.html
<h1 class="title"><span>I am fuga.</span></h1>

うまくいった!

ドキュメント

oieioi
ハマったポイントをメモする。
https://oieioi.github.io/
tsukulink
建設業マッチングサイト「ツクリンク」の開発・運営
https://tsukulink.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away