Rails частичный рендеринг шаблона несколько раз, когда вспомогательный метод использует ключевое слово yield
Я видел странное поведение при использовании рельсов с частичной разметкой плюс вспомогательный метод, закодированный как итератор с использованием ключевого слова yield. Я надеюсь, что кто-то может:
- Объясните, что происходит и почему я получаю дубликат рендеринга и, возможно,
- Предложите альтернативный подход, надеюсь, помимо простого перекодирования моего вспомогательного метода в простую функцию, которая возвращает список (я уже сделал это в качестве временного обходного пути)
Поэтому, если я создаю следующие 3 вещи в своем приложении rails 3, я получаю неожиданный вывод.
[ОБНОВЛЕНИЕ] Я проверил следующие комбинации:
Rails 3.0.0 + erb (has this issue)
Rails 3.0.0 + haml (OK)
Rails 3.0.3 + erb (has this issue)
Rails 3.0.3 + haml (OK)
Так что, может быть, это что-то типа эрб против хамла, но когда я впервые обнаружил это, это было в хамл-шаблонах. Хммм.... кто-нибудь знает, что происходит???
A) Основной шаблон, который выглядит следующим образом (app/views/main/index.html.erb)
<h1>Main#index</h1>
<p>This is content from main#index before the partial template rendering
<%= render :partial => "partial" %>
<p>This is content from main#index after the partial template rendering.</p>
Б) вспомогательный метод, подобный этому (app / helpers / main_helper.rb)
module MainHelper
def my_iterator
yield 1
yield 2
yield 3
yield 4
end
end
C) Частичный шаблон, подобный этому (app/views/main/_partial.html.erb)
<% my_iterator do |x| %>
<p>iterator running with <%= x %></p>
<% end %>
Когда я просматриваю результат в браузере, я вижу блок "Итератор работает с" в общей сложности 8 раз (1 2 3 4 1 2 3 4). Я определил, что это доходность в завинчивании my_iterator с механизмом частичного шаблона рельсов. Если я кодирую my_iterator следующим образом, вывод будет таким, как я ожидал. (Мне также нужно изменить мой частичный шаблон, чтобы сделать my_iterator.each)
def my_iterator
logger.debug("my_iterator called")
return [1, 2, 3, 4]
end
Есть ли способ закодировать это так, чтобы я не привинчивался к рельсам и не получал дублирующийся рендеринг, но все еще мог закодировать вспомогательный метод как итератор, использующий yield? Кроме того, кто-то может объяснить, как именно происходит дублирование рендеринга?
3 ответа
У меня была очень похожая проблема, и мне удалось ее решить. Я полагаю, что оригинальный помощник выше будет работать так, как ожидалось, если переписать его как таковой...
module MainHelper
def my_iterator(&block)
block.call(1)
block.call(2)
block.call(3)
block.call(4)
end
end
Похоже, такая же проблема возникает в Rails 3, если ваш вызов concat(capture(&block))
или же concat(block.call)
, В обоих случаях просто бросьте concat()
и дублирование рендеринга исчезает.
У меня была похожая проблема, которая появилась только в производстве, а не в разработке. Я сузил это до
config.action_view.cache_template_loading = true
в моем развитии. Когда установлено значение true, я увидел элементы в моем файле haml. Добавляя и удаляя блоки, я сузил код ошибки до
= if @user.bio
= @user.bio
который заставлял весь блок, который предшествовал этому, быть перепечатан. Простая замена = на - решает это. Отладка была неловкой просто потому, что мне приходилось делать отладку в производственном режиме.
Мой совет - искать ошибочные = выходы для логических операторов.
- if @user.bio
= @user.bio
Использование content_for внутри помощника будет добавлять контент на каждой итерации. Вы можете написать метод ApplicationHelper для получения содержимого в помощниках следующим образом:
def yield_content(content_key)
view_flow.content.delete(content_key)
end
Затем используйте yield_content вместо content_for в других ваших вспомогательных файлах.