当辅助方法使用yield关键字时,Rails会重复执行部分模板渲染

时间:2010-11-18 03:07:35

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

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

  1. 解释发生了什么以及为什么我会得到重复的渲染,也许
  2. 建议一种替代方法,希望不仅仅是将我的帮助方法重新编码为一个返回列表的简单函数(我已经将其作为临时解决方法)
  3. 因此,如果我在rails 3应用程序中创建以下3项内容,则会出现意外输出。

    [UPDATE] 我测试了以下组合:

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

    当我在浏览器中查看结果时,我看到“迭代器正在运行”块总共8次(1 2 3 4 1 2 3 4)。我已经确定它是my_iterator中与rails部分模板机制拧紧的产量。如果我按如下方式编码my_iterator,输出就像我期望的那样。 (我还需要将部分模板更改为my_iterator.each)

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

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

3 个答案:

答案 0 :(得分:3)

我只是遇到了一个非常类似的问题而且设法解决了这个问题。我相信上面的原始助手如果重写它就会按预期工作......

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

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

答案 1 :(得分:1)

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

    config.action_view.cache_template_loading = true

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

    = if @user.bio
      = @user.bio

导致重新打印之前的整个块。简单地替换= with - 解决这个问题。调试很尴尬因为我必须在生产模式下进行调试。

我的建议是在逻辑运算符上查找errant = outputs。

    - if @user.bio
      = @user.bio

答案 2 :(得分:0)

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

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

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