Search code examples
ruby-on-railsruby-on-rails-5actionview

Discrepancy when capturing Rails view block


I have an ERB view with two blocks:

<%= test_h1 do %>
  <%= 'test1' %>
<% end -%>

<%= test_h2 do %>
  <%= 'test2' %>
<% end -%>

where test_h1 and test_h2 are similar helpers, but one is defined in a helper file, while another via helper_method in a controller:

module TestHelper
  def test_h1(&block)
    link_to '/url' do
      capture(&block)
    end
  end
end

class TestController < ApplicationController
  helper_method :test_h2

  def test_h2(&block)
    helpers.link_to '/url' do
      helpers.capture(&block)
    end
  end
end

test_h1 produces the expected result and test_h2 renders the inner template block first:

<a href="/url">test1</a>

test2<a href="/url"></a>

Why? What would be an idiomatic way to write test_h2 ?


Solution

  • capture overrides current output buffer and just calls the block (which is still bound to other view context), thus override has no effect when called from controller because view_context is not the same context the view is being rendered in.

    To work around contexts you can define your helper like so:

    # in controller
    helper do
      def test_h3(&block)
        # this will run in view context, so call `controller.some_func` to access controller instance
        link_to '/url' do
          capture(&block)
        end
      end
    end