Written June 18, 2013. Tagged Ruby on Rails, Helpers.
You can use the built-in Rails helpers, such as content_tag
or link_to
, in your own helpers.
If you need to concatenate them, you could use +
:
module MyHelper
def widget
content_tag(:p, class: "widget") do
link_to("Hello", hello_path) + " " + link_to("Bye", goodbye_path)
end
end
end
But this gets fiddly quick.
concat
Instead, you can use concat
:
module MyHelper
def widget
content_tag(:p, class: "widget") do
concat link_to("Hello", hello_path)
concat " "
concat link_to("Bye", goodbye_path)
end
end
end
Each concat(content)
adds that content to the output buffer, much like <%= content %>
will in a template file.
capture
There's a gotcha when you use concat
outside a block helper (outside e.g. a content_tag
or link_to
block).
Say you have this:
module MyHelper
def widget
concat link_to("Hello", hello_path)
concat " "
concat link_to("Bye", goodbye_path)
end
end
You might expect this to produce no output, but you'll see the output once:
<% widget %>
You might expect this to produce the output once, but it will appear twice:
<%= widget %>
Why? Inside block helpers, concat
appends only to that element's content; outside block helpers, it appends straight to the page itself, and is then appended to the page again as <%= widget %>
writes out the helper's return value.
You can get around this with the capture
helper. That's what content_tag
uses internally: capture
, true to its name, captures the content so it isn't appended straight to the page. Instead, it's built up as a separate string, for your custom helper to return (or have its way with):
module MyHelper
def widget
capture do
concat link_to("Hello", hello_path)
concat " "
concat link_to("Bye", goodbye_path)
end
end
end
If you find yourself writing a lot of complex markup in a helper, you may of course be better served by rendering a partial – perhaps from within your helper. But for those cases with a lot of logic influencing the choice of elements or attributes, where a helper may be the best option, concat
and capture
can clean things up a bit.