【问题标题】:Rails partial template rendering repeatedly when a helper method uses the yield keyword当辅助方法使用 yield 关键字时,Rails 部分模板重复呈现
【发布时间】:2011-05-11 19:29:30
【问题描述】:

在使用带有部分布局的rails 以及使用yield 关键字编码为迭代器的辅助方法时,我看到了一些奇怪的行为。我希望有人可以:

  1. 解释发生了什么以及为什么我得到重复的渲染,也许
  2. 建议一种替代方法,希望不仅仅是将我的辅助方法重新编码为一个返回列表的简单函数(我已经将其作为临时解决方法)

因此,如果我在我的 rails 3 应用程序中创建以下 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)

所以也许这是一个 erb 与 haml 的事情,但当我最初发现它时,它是在 haml 模板上。嗯……有谁知道怎么回事???

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 %>

当我在浏览器中查看结果时,我看到“iterator running with”总共阻塞了 8 次(1 2 3 4 1 2 3 4)。我已经确定它是 my_iterator 中的 yield 与 rails 部分模板机制有关。如果我对 my_iterator 进行如下编码,则输出与我预期的一样。 (我还需要更改我的部分模板来执行 my_iterator.each)

def my_iterator
  logger.debug("my_iterator called")
  return [1, 2, 3, 4]
end

有没有办法对此进行编码,这样我就不会使用 rails 并获得重复的渲染,但仍然可以使用 yield 将辅助方法编码为迭代器?另外,有人能解释一下重复渲染是如何发生的吗?

【问题讨论】:

  • 仅供参考,我在带有 Haml 的 Rails 3.0.3 中没有这种行为。
  • 我会尝试使用 3.0.3,看看它是否会消失。
  • 用 rails 3.0.3 试过了。同样的问题。仅供参考,我在最初发现这个问题的生产环境中使用了 haml,但为了简单起见,这里使用 erb 作为问题,但两者似乎都表现出这一点。
  • 啊。有趣,单片眼镜。我编写了相同的场景,但使用 haml 模板引擎,在我的小测试应用程序中,rails 3.0.3 中不存在问题。
  • 在 Ruby 1.8.7p0 上使用 Rails 3.0.3 确认此问题。但不会发生在 Rails 2.3.8 上。另外,看看这张票是否相关:rails.lighthouseapp.com/projects/8994/tickets/…

标签: ruby-on-rails-3 partial-views renderpartial yield-keyword


【解决方案1】:

我遇到了类似的问题,它只出现在生产中,而不是开发中。我把范围缩小到

    config.action_view.cache_template_loading = true

在我的 development.rb 中。当设置为 true 时,我在我的 haml 文件中看到了一个元素。通过添加和删除块,我将有问题的代码缩小到

    = if @user.bio
      = @user.bio

这导致重新打印之前的整个块。只需将 = 替换为 - 即可解决此问题。调试很尴尬,因为我必须在生产模式下进行调试。

我的建议是寻找 errant = 逻辑运算符的输出。

    - if @user.bio
      = @user.bio

【讨论】:

    【解决方案2】:

    在帮助程序中使用 content_for 将在每次迭代中附加内容。您可以编写一个 ApplicationHelper 方法来在助手中生成内容,如下所示:

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

    然后在您的其他帮助文件中使用 yield_content 而不是 content_for。

    【讨论】:

      【解决方案3】:

      我刚刚遇到了一个非常相似的问题,并且设法解决了它。我相信如果将上面的原始助手重写为这样,它会按预期工作......

      module MainHelper
        def my_iterator(&block)
          block.call(1)
          block.call(2)
          block.call(3)
          block.call(4)
        end
      end
      

      如果您调用concat(capture(&amp;block))concat(block.call),Rails 3 中似乎也会出现同样的问题。在这两种情况下,只需删除 concat(),重复的渲染就会消失。

      【讨论】:

      • 感谢乔恩的回答!我目前不再专注于这个项目,但下次我回去做一些更新时,我会试试这个并告诉你结果。
      • 实际上,我再次让它在开发中正常工作,并在生产中两次渲染。还是被难住了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-25
      • 2011-03-27
      相关资源
      最近更新 更多