crispy
crispy

Reputation: 5877

Mysterious Ruby Block behavior: &block vs. {block.call}

When writing a helper for printing javascript that can be used from both other helpers and views, I stumbled upon the following problem:

def javascript(print_tag = false, &block)
  content_for(:javascript) do
    if print_tag
      javascript_tag(&block)          # does not work
      javascript_tag { block.call }   # does work 
    else
      capture(&block)
    end
  end
end

This helper should be called with javascript { "alert('hurray'); }.

In the first alternative - which I expected to work - the Rails javascript_tag helper renders an empty <script type="text/javascript"> //<![CDATA[ //]]> </script> tag.

The second alternative, however, works as expected.

What's going on there? How can that be different?

Upvotes: 4

Views: 386

Answers (1)

tokland
tokland

Reputation: 67850

You say you are doing this on your views, right?

<%= javascript { "alert('hurray');" } %>

But for content_tag(&block) to work, you should call javascript the way content_tag is intended to be used in views, which is:

<% javascript do %>
  alert('hurray');
<% end %>

content_tag's behavior is different depending on where it's called from, see the function block_called_from_erb? in the source code. In the first case this function returns true because the block does come from an erb (and then it's concated, you don't want that!), in the second returns false (you re-created the block from scratch) and content_tag simply returns the string content, which is what you want.

# ./action_view/helpers/javascript_helper.rb
tag = content_tag(:script, javascript_cdata_section(content), html_options.merge(:type => Mime::JS))
if block_called_from_erb?(block)
  concat(tag)
else
  tag
end

Upvotes: 4

Related Questions