简体   繁体   中英

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?

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 concat ed, 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM