当我生成视图中提供的哈希时,如何覆盖 ActiveSupport::SafeBuffer

How do I override ActiveSupport::SafeBuffer when I yield a hash provided in a view

我的 profile.html.erb 提供了 layout.html.erb 上游的散列,以包含在元数据中

  <% provide(:twitter, { %>
  <% card: 'summary', %>
  <% site: '@twitter', %>
  <% title: 'Lorem ipsum', %>
  <% description: 'Non sequitar', %>
  <% image: gravatar_for(@user, { size: 150 } )%>
  <% }) %>

然后 layout.html.erb 应该对此进行迭代并创建元标记:

  <% yield(:twitter).each do |key, value|%>
  <meta name="twitter:#{key}" content="#{value}" />
  <% end %>

但是,它给了我错误 undefined method 'each' for #<ActiveSupport::SafeBuffer:0x007f8d616e5870>,并且在用 byebug 检查了 yield(:twitter) 之后,我看到我产生了一个 ActiveSupport::SafeBuffer:[=22= 的实例]

(byebug) hash = yield(:twitter)
"{:card=&gt;&quot;summary&quot;, :site=&gt;&quot;@twitter&quot;, :title=&gt;&quot;Lorem ipsum&quot;, :description=&gt;&quot;Non sequitar&quot;, :image=&gt;&quot;https://secure.gravatar.com/avatar/a937016807c66d89d0a62d7a1b235533?s=150&quot;}"
(byebug) hash.class
ActiveSupport::SafeBuffer

我可以将字符串评估为散列,但 ActiveSupport::SafeBuffer 对其进行编码 html 是安全的,并且没有办法将原始字符串取回。有没有更聪明的方法来做到这一点,还是我必须用一个助手将字符串转换回哈希,然后 eval() 将它变成 has?

我用以下方法修复了它:

  <% twitter_tags = String.new yield(:twitter)%>
  <% twitter_tags = eval ( CGI.unescapeHTML( twitter_tags ) ) %>

  <% twitter_tags.each do |key, value|%>
    <%= tag(:meta, name: "twitter:#{key}", content: (value) )%>
  <% end %>

恕我直言,这是一种极其丑陋的解决问题的方法。我会写一个帮助程序来从视图中删除大部分内容,但是,如果您有更优雅的解决方案,请分享它,我会接受您的回答而不是我的。

默认情况下,所有提供的值都是 ActiveSupport::SafeBuffer 的实例,这会将其转换为字符串,并再次将其计算为散列。

由于提供需要字符串或块,因此最好在帮助程序中创建元标记并将其作为字符串参数传递。

module TwitterHelper
  def twitter_meta_tags(hash)
     hash.each_with_object([]) do |(key, value), array|
        a.push( tag(:meta, { name: "twitter:#{k}", content: v }, false, false ) )
     end.join("\n").html_safe
     # not sure if that last html_safe is really needed.
  end
end

下游视图:

<%
provide(:twitter, twitter_meta_tags({
  foo: "bar"
}));
%>

布局:

<%= yield(:twitter) %>

使用部分

另一种选择是使用部分并将块而不是字符串传递给 provide:

<% # app/views/twitter/_meta_tags.html.erb %>
<% hash.each do |key, value|%>
  <meta name="twitter:#{key}" content="#{value}" />
<% end %>

下游视图:

<% provide(:twitter) do %>
  <%= render partial: "twitter/meta_tags", hash: {
    card: 'summary', 
    site: '@twitter',
    title: 'Lorem ipsum',
    description: 'Non sequitar',
    image: gravatar_for(@user, { size: 150 } )
  } %>
<% end %>

布局:

<%= yield(:twitter) %>