Для справки, вот определение concat, с которым вы сталкиваетесь при выполнении этого кода (из actionpack / lib / action_view / helpers / tag_helper.rb).

аюсь вспомогательный метод, который выведет список элементов, которые будут вызываться так:

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)

Вы могли бы использоватьcontent_tag_for, который работает с коллекциями:

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

Обновить: В Rails 5content_tag_for (а такжеdiv_for) были перенесены в отдельный драгоценный камень. Вы должны установитьrecord_tag_helper драгоценный камень, чтобы использовать их.

 hellion22 сент. 2016 г., 00:31
content_tag_for удален в Rails 5

Если бы вы использовали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", "#"), ... ])

Вывод будет правильно рассчитан.

 David J.16 июн. 2012 г., 22:23
Спасибо, это супер гладко!

что 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

(1..14).to_a.each do |age|
  concat content_tag :li, "#{link_to age, '#'}".html_safe
end
 nruth17 февр. 2016 г., 21:31
При этом может потребоваться изменить <% = на <% в шаблоне.
Решение Вопроса

Попробуй это:

def foo_list items
  content_tag :ul do
      items.collect {|item| concat(content_tag(:li, item))}
  end
end
 Tallboy19 апр. 2018 г., 20:04
Спасибо, я не мог найти этот метод раньше. Что объясняет его
 zetetic19 апр. 2018 г., 19:44
@Высокий мальчикconcat здесь объясняется:api.rubyonrails.org/classes/ActionView/Helpers/..., Метод вызывается в контексте представления (я думаю). Вы можете спутать это сString#concat
 Tallboy19 апр. 2018 г., 04:37
Можете ли вы объяснить, как работает concat здесь? Я думал, что concat должен быть вызван на другом объекте?
 DEfusion13 янв. 2011 г., 12:14
Это работает, я попытался сделать конкат на сбор, раньше, а не внутри. С concat внутри proc, собирать не нужно, и вы можете использовать items.each (или другие итераторы).
 Ivailo Bardarov13 мар. 2011 г., 17:56
Таким образом, вы вызываете concat для каждого элемента. Я думаю, что было бы дешевле сделать items.collect {}. Join (""). Html_safe

Ваш ответ на вопрос