Цикл и выводить content_tags в пределах content_tag в помощнике
Я пытаюсь вспомогательный метод, который будет выводить список элементов, которые будут вызываться так:
foo_list( ['item_one', link_to( 'item_two', '#' ) ... ] )
Я написал помощник так после прочтения Использование помощников в рельсах 3 для вывода 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
должен работать в режиме блока с коллекцией как-то.
5 ответов
Попробуй это:
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
) были перенесены в отдельный драгоценный камень. Вы должны установить record_tag_helper
драгоценный камень для того, чтобы использовать их.
Наряду с ответами выше, это работало для меня хорошо:
(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