在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