Поведение таинственного рубинового блока: & block vs. {block.call} - PullRequest
4 голосов
/ 20 декабря 2010

При написании помощника для печати javascript, который может использоваться как другими помощниками, так и представлениями, я наткнулся на следующую проблему:

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

Этот помощник должен вызываться с помощью javascript { "alert('hurray'); }.

В первом варианте - который я ожидал сработать - Rails помощник javascript_tag отображает пустой тег <script type="text/javascript"> //<![CDATA[ //]]> </script>.

Второй вариант, однако, работает как положено.

Что там происходит?Как это может отличаться?

1 Ответ

4 голосов
/ 20 декабря 2010

Вы говорите, что делаете это со своими взглядами, верно?

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

Но чтобы content_tag(&block) работал, вы должны назвать javascript способом content_tag, предназначенным для использования в представлениях, а именно:

<% javascript do %>
  alert('hurray');
<% end %>
Поведение

content_tag отличается в зависимости от того, откуда он вызывается, см. Функцию block_called_from_erb? в исходном коде. В первом случае эта функция возвращает true, потому что блок происходит из erb (а затем он concat ed, вы не хотите!), Во втором возвращает false (вы воссоздали блок с нуля) и content_tag просто возвращает содержимое строки, что вам и нужно.

# ./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
...