Rails частичный рендеринг шаблона повторно, когда вспомогательный метод использует ключевое слово yield - PullRequest
2 голосов
/ 18 ноября 2010

Я видел странное поведение при использовании рельсов с частичной разметкой плюс вспомогательный метод, закодированный как итератор с использованием ключевого слова yield.Я надеюсь, что кто-то может:

  1. Объяснить, что происходит и почему я получаю дублированный рендеринг и, возможно,
  2. Предложить альтернативный подход, надеюсь, отличный от простого перекодирования моего вспомогательного метода вбыть простой функцией, которая возвращает список (я уже сделал это как временное решение)

Так что, если я создаю следующие 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>

B) Вспомогательный метод, подобный этому (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 ]

3 голосов
/ 23 июня 2011

У меня была очень похожая проблема, и мне удалось ее решить.Я полагаю, что оригинальный помощник, приведенный выше, будет работать так, как ожидалось, если переписать его таким образом ...

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(), и дублированный рендеринг исчезнет.

1 голос
/ 13 сентября 2011

У меня была похожая проблема, которая появилась только в производстве, а не в разработке.Я сузил это до

    config.action_view.cache_template_loading = true

в моем development.rb.Когда установлено значение true, я увидел элементы в моем файле haml.Добавляя и удаляя блоки, я сузил код ошибки до

    = if @user.bio
      = @user.bio

, что привело к перепечатке всего блока, который предшествовал этому.Простая замена = на - решает это.Отлаживать было неудобно просто потому, что мне приходилось делать отладку в производственном режиме.

Мой совет - искать ошибочные = выходы для логических операторов.

    - if @user.bio
      = @user.bio
0 голосов
/ 14 ноября 2012

Использование content_for внутри помощника будет добавлять контент на каждой итерации.Вы можете написать метод ApplicationHelper для выдачи контента внутри помощников, например:

def yield_content(content_key)
  view_flow.content.delete(content_key)
end

Затем используйте yield_content вместо content_for в других файлах помощника.

...