在helper中循环和输出content_tag中的content_tags

31

我正在尝试编写一个帮助方法,用于输出一组条目,可以通过如下方式调用:

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

在阅读 Rails 3 中使用 helper 输出 HTML 后,我编写了如下的 helper:

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

我得到了预期的无序列表和列表项。

我尝试过一些调整,如:

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应该以某种方式以块模式与集合一起使用。

5个回答

55

试试这个:

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

可以这样做,我之前尝试过在collect周围进行concat,而不是在其中。将concat放在proc内部,就不需要使用collect了,可以使用items.each(或其他迭代器)。 - DEfusion
3
您正在对每个元素调用concat方法。我认为,使用items.collect{}.join("").html_safe会更省钱。 - Ivailo Bardarov
你能解释一下这里concat是如何工作的吗?我以为concat必须在另一个对象上调用? - Tallboy
2
@Tallboy 这里有concat的解释:http://api.rubyonrails.org/classes/ActionView/Helpers/TextHelper.html#method-i-concat。该方法在视图上下文中被调用(我认为)。你可能把它和`String#concat`搞混了。 - zetetic
谢谢,我之前找不到那个方法。这解释了一切。 - Tallboy

8

我无法让它更好地工作。

如果您已经在使用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", "#"), ... ])

输出将会被正确地呈现。


5
您可以使用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才能使用它们。


content_tag_for在Rails 5中已被移除。 - hellion

4
除了上面的答案之外,下面这个对我也有效:

...

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

2
在执行此操作时,可能需要将模板中的<%=更改为<%。 - nruth

2

问题在于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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接