you are supposed to write your helpers to return their result as text,
rather than append to the accumulating content.
How do I execute the code in the block that has been passed to the
helper without it appending to the content? My instincts, which are
clearly wrong, are to just use "yield" like I would in any other method
that takes a block. However, within the context of a helper method.
"yield" seems to have a side effect of appending to the accumulating
content. So, I have to do the following to suppress the intended output
of the helper because the yield is already appending it:
module FooHelper
def none_if_empty
yield
return ''
end
end
What is the proper way to write this helper in Rails 3?
We're having this problem with Rails 3. Helpers what worked in Rails 2
are basically this:
def helper(&block)
block.call # Returns the entire partial up to the helper call twice
end
Adding
return ''
to the end helps, but as Avram said, this is only the behavior I'd
expect if the helper was called with "<%= %>". In our testing, calling
with and without the = made no difference.
If you look at the compiled template, any <% %> blocks are compiled to
something like this:
_buf << '<div ...'
Hence if you had the following (silly) ERB:
<% foo do |b| %>
<li <%= b %> >
<% end %>
the block portion would get compiled to:
_buf << '<li ';
_buf << ( b )
_buf << ' >'
Hence, if you yield to this block, the return value of the yield will be
_buf. _buf contains the portion of the template that has been rendered
so far. And if the yield is the last statement, then the implicit return
value will be _buf.
So far so good. Now you're wondering, hey, the output should not be in
the template unless you're using <%= %>, right? This should be true, but
in the interest of backwards compatibility, Rails 3 has
append_if_string= - this appends the return value of <% %> blocks if the
value is a string (so old form_for's, etc. don't break). _buf is
conveniently a string as well, and gets added to the page.
module NavigationHelper
def nav_item(link_text, link_path)
nav_link_class = if current_page? link_path
"nav-link active"
else
"nav-link"
end
content_tag :li, nil, class: "nav-item" do
link_to link_path, class: nav_link_class do
concat content_tag(:span, nil, class: "nav-icon")
concat link_text
concat capture { yield } if block_given?
end
end
end
end