View helper, blocks and capture. Template output is repeated (rails 3)

I’m having some issues with blocks and capture in erb templates, and
the particular problem shows itself in that the expected output in the
template view is repeated due to something related to how capture
works. (Using Rails 3.x)

I have the following view helper:

module ColumnLayoutHelper

def layout_columns(options = {}, &content_block)
raise ArgumentError, “No block given” unless block_given?

layout = ColumnLayoutBuilder.new
layout.configure(options)
content = capture(layout, &content_block)
content_tag(:div, content, layout.main_wrapping, false)

end

end

class ColumnLayoutBuilder < Object

include ActionView::Helpers::TagHelper
include ActionView::Helpers::CaptureHelper

attr_accessor :output_buffer, :column_counter
attr_accessor :main_wrapping
attr_accessor :column_wrapping

def configure(options)
@main_wrapping = options.delete(:main_wrapping)
@column_wrapping = options.delete(:column_wrapping)
end

def column(&block)

raise ArgumentError, "No block given" unless block_given?

@column_counter ||= 0
@column_counter = @column_counter + 1

column_html_options = (column_wrapping ? column_wrapping.dup : {})

|| {}
column_html_options.default = “”
column_html_options[:class] = "column_#{column_counter} " +
column_html_options[:class]
column_content = content_tag(:div, capture(self, &block),
column_html_options,false)
column_content
end

end

Now if I use this column builder helper with the following erb
template:

<%= layout_columns do |layout| %>
<%= layout.column do %>
content_01
<% end %>
<%= layout.column do %>
content02
<% end %>
<% end %>

I get the following output.

content_01
content_01
content02
content_01
content_01
content02

As you can see, the buffer in between the captures doesn’t seem to be
cleared in the separate block scopes. As I sort of expected how
capture would work…

I guess I’m having the same issues as pointed out here

Any ideas on how to fix this? Thanks

On 14 Apr 2011, at 23:26, christoffer [email protected]
wrote:

I’m having some issues with blocks and capture in erb templates, and
the particular problem shows itself in that the expected output in the
template view is repeated due to something related to how capture
works. (Using Rails 3.x)

Here’s my hunch: capture swaps in a temporary output buffer to capture
the output. However because you’ve got your custom builder object, the
call to capture inside your builder object is fiddling with the
builder’s output buffer attribute, which is neither here nor there
because the bits of erb you yield to know nothing of this arrangement an
d are writing to the template’s output_buffer

If you look at the source for fields_for/Formbuilder you can see that
they squirrel away the template object (in your helper method this is
just self) for later. You should probably do the same

Fred