method

concat

rails latest stable - Class: ActionView::Helpers::TextHelper
concat(string)
public

The preferred method of outputting text in your views is to use the <%= "text" %> eRuby syntax. The regular puts and print methods do not operate as expected in an eRuby code block. If you absolutely must output text within a non-output code block (i.e., <% %>), you can use the concat method.

<% concat "hello" %> is equivalent to <%= "hello" %>

<%
   unless signed_in?
     concat link_to("Sign In", action: :sign_in)
   end
%>

is equivalent to

<% unless signed_in? %>
  <%= link_to "Sign In", action: :sign_in %>
<% end %>

6Notes

helper method to partial

autonomous · Jul 21, 200814 thanks

concat can be useful for rendering a block to a partial from a helper:

def block_to_partial(partial_name, options = {}, &block)
options.merge!(:body => capture(&block))
concat(render(:partial => partial_name, :locals => options), block.binding)
end

This would be particularly useful if you had some partial to help you out with rounded corners, for example. So, in your helper:

def rounded_corners &block block_to_partial("shared/rounded_corners", {}, &block) end

In your view you could have something like:

<% rounded_corners do -%> This text is surrounded by rounded corners <% end -%>

You would have to create some partial in app/views/shared/rounded_corners.html.erb

And it would look something like:

. . . <%= body -%>

Re: Helper method taking a block

LacKac · Aug 13, 20087 thanks

The same using the ActionView::Helpers::TagHelper#content_tag and ActionView::Helpers::CaptureHelper#capture methods:

def render_tree(collection, &block)
concat(
  content_tag(:ul,
    collection.collect { |item|
      content_tag(:li, capture(item, &block))
    }.join("\

") ), block.binding ) end

The benefit is that it's easier to improve with html attributes (just add a hash of options to the +content_tag+ call) and it makes just one call to concat (which probably makes it faster).

Helper method taking a block

hosiawak · Aug 12, 20086 thanks

Following the similar egzample by autonomous, here's a simpler version when you just need to write a flexible helper method that takes a block.

For example, suppose you have a method that renders a tree:

def render_tree(ary, &block)
concat("<ul>", block.binding)
for elem in ary
  concat("<li>", block.binding)
  yield elem
  concat("</li>", block.binding)
end
concat("</ul>", block.binding)
end

You can use it in your view, eg:

<% render_tree(@objects) do |elem| -%>
<%= elem.title -%>
<%= link_to 'delete', elem -%>
<% end -%>

that would return for egzample:

=== Testing concat

To test such helper methods, use the following pattern (a utility method added to your Rspec/unit test suite:

def render_for(root, options = {})
_erbout = ''
render_tree(root, options) do |node|
  _erbout.concat(node.title)
end
_erbout
end

and test like this (RSpec example):

it "should return abc" do
render_for(object).should == 'abc'
end

Iterate and join blocks

tokland · Aug 20, 20085 thanks

Following LacKac's idea, we can write render_join (useful to render a collection with a small chunks of code, where a render :partial + :spacer_template would be overkill):

def render_join(collection, join_string, &block)
output = collection.collect do |item| 
  capture(item, &block)
end.join(join_string)
concat(output, block.binding)
end

An example of use:

<% render_join(@items, '<br />') do |item| %>
 <p>Item title: <%= item.title %></p>
<% end %>

Binding parameter deprecated in > 2.2

mikael · Aug 4, 20091 thank

Supplying the binding argument produces a deprecation warning in 2.2 and newer:

DEPRECATION WARNING: The binding argument of #concat is no longer needed. Please remove it from your views and helpers.

Capturing blocks after >2.2

mechazoidal · Dec 3, 20091 thank

After 2.2, you can omit the do ...end block and simply use the &block variable directly: concat(content_tag(:div, :class => "wrapped_content") do capture(&block) end, block.binding)

becomes simply:

concat(content_tag(:div, capture(&block), :class => "wrapped_content"))