在helper中的content_tag内循环并输出content_tags

我正在尝试一个帮助方法,它将输出一个项目列表,如下所示:

foo_list( ['item_one', link_to( 'item_two', '#' ) ... ] ) 

我在阅读了使用rails 3中的helper输出html之后,就像这样编写了帮助器:

 def foo_list items content_tag :ul do items.collect {|item| content_tag(:li, item)} end end 

但是,如果我这样做,我只是在这种情况下得到一个空的UL:

 def foo_list items content_tag :ul do content_tag(:li, 'foo') end end 

我按预期获得了UL和LI。

我已经尝试过将它交换一下:

 def foo_list items contents = items.map {|item| content_tag(:li, item)} content_tag( :ul, contents ) end 

在这种情况下,我得到整个列表,但LI标签是html转义(即使字符串是HTML安全)。 做content_tag(:ul, contents.join("\n").html_safe )有效,但我感觉不对,我觉得content_tag应该以块模式工作,并以某种方式收集。

试试这个:

 def foo_list items content_tag :ul do items.collect {|item| concat(content_tag(:li, item))} end end 

我无法更好地完成这项工作。

如果您已经使用HAML ,您可以像这样编写助手:

 def foo_list(items) haml_tag :ul do items.each do |item| haml_tag :li, item end end end 

从视图中使用:

 - foo_list(["item_one", link_to("item_two", "#"), ... ]) 

输出将是正确的意图。

您可以使用content_tag_for ,它适用于集合:

 def foo_list(items) content_tag(:ul) { content_tag_for :li, items } end 

更新:在Rails 5中, content_tag_for (和div_for )被移动到一个单独的gem中。 您必须安装record_tag_helper gem才能使用它们。

除了上面的答案,这对我很有用:

 (1..14).to_a.each do |age| concat content_tag :li, "#{link_to age, '#'}".html_safe end 

最大的问题是,content_tag在接收数组时没有做任何智能,你需要发送已经处理过的内容。 我发现这样做的一个好方法是折叠/减少你的数组以将它们连接在一起。

例如,您的第一个和第三个示例可以使用以下代码而不是您的items.map/collect行:

 items.reduce(''.html_safe) { |x, item| x << content_tag(:li, item) } 

作为参考,这里是执行此代码时遇到的concat的定义(来自actionpack / lib / action_view / helpers / tag_helper.rb)。

 def concat(value) if dirty? || value.html_safe? super(value) else super(ERB::Util.h(value)) end end alias << concat