Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a helper with block?

I want to make a helper like the following.

def my_div some_options, &block
  # How do I print the result of the block?
end
like image 728
Sam Kong Avatar asked Jun 26 '09 07:06

Sam Kong


2 Answers

You should use CaptureHelper.

def my_div(some_options, &block)
  # capture the value of the block a string
  content = capture(&block)
  # concat the value to the output
  concat(content)
end

<% my_div([]) do %>
  <p>The content</p>
<% end %>


def my_div(some_options, &block)
  # capture the value of the block a string
  # and returns it. You MUST use <%= in your view.
  capture(&block)
end

<%= my_div([]) do %>
  <p>The content</p>
<% end %>

Use capture + concat if you need to concat the output. Use capture if you need to capture and then reuse the content. If your block doesn't explicitely use <%=, then you MUST call concat (preferred way).

This is an example of a method that hides the content if the user it not an admin.

def if_admin(options = {}, &block)
  if admin?
    concat content_tag(:div, capture(&block), options)
  end
end

<% if_admin(:style => "admin") do %>
<p>Super secret content.</p>
<% end %>
like image 85
Simone Carletti Avatar answered Sep 28 '22 17:09

Simone Carletti


so two things that are important:

  • rails ignores anything that isn't a string in a content_tag (and content_for)
  • you can't use Array#join (etc.) because it produces unsafe strings, you need to use safe_join and content_tag to have safe strings
  • I didn't need either capture or concat in my case.
  def map_join(objects, &block)
    safe_join(objects.map(&block))
  end

  def list(objects, &block)
    if objects.none?
      content_tag(:p, "none")
    else
      content_tag(:ul, class: "disc") do
        map_join(objects) do |object|
          content_tag(:li) do
            block.call(object)
          end
        end
      end
    end
  end

this can be used like this:

= list(@users) do |user|
  => render user
  = link_to "show", user 

(this is slim but works fine with erb too)

like image 28
localhostdotdev Avatar answered Sep 28 '22 17:09

localhostdotdev