【问题标题】:Discrepancy when capturing Rails view block捕获 Rails 视图块时的差异
【发布时间】:2019-05-15 15:07:56
【问题描述】:

我有一个包含两个块的 ERB 视图:

<%= test_h1 do %>
  <%= 'test1' %>
<% end -%>

<%= test_h2 do %>
  <%= 'test2' %>
<% end -%>

其中test_h1test_h2 是相似的助手,但一个是在助手文件中定义的,而另一个是通过控制器中的helper_method 定义的:

module TestHelper
  def test_h1(&block)
    link_to '/url' do
      capture(&block)
    end
  end
end

class TestController < ApplicationController
  helper_method :test_h2

  def test_h2(&block)
    helpers.link_to '/url' do
      helpers.capture(&block)
    end
  end
end

test_h1 产生预期的结果,test_h2 首先呈现内部模板块:

<a href="/url">test1</a>

test2<a href="/url"></a>

为什么?写test_h2 的惯用方式是什么?

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-5 actionview


    【解决方案1】:

    我认为这两个视图示例都应该重写为:

    <%= test_h1 do %>
      <% 'test1' %>
    <% end -%>
    
    <%= test_h2 do %>
      <% 'test2' %>
    <% end -%>
    

    我的理解是 '

    【讨论】:

    【解决方案2】:

    capture 覆盖当前输出缓冲区并仅调用块(仍绑定到其他视图上下文),因此从控制器调用时覆盖无效,因为view_context 与视图呈现的上下文不同.

    要解决上下文,您可以像这样定义您的助手:

    # in controller
    helper do
      def test_h3(&block)
        # this will run in view context, so call `controller.some_func` to access controller instance
        link_to '/url' do
          capture(&block)
        end
      end
    end
    

    【讨论】:

    • 感谢您对如何定义辅助方法的解释和建议。公共 API 似乎是 helper do def test_h3...; end,它在 helper 的 API 文档中进行了描述(在内部它完全是 _helpers.module_eval
    【解决方案3】:

    当从您的控制器使用capture 时,输出会附加到页面缓冲区,因此您的erb 的&lt;%= 会立即输出到页面输出。

    要解决此问题,您需要在 test_h2 块中使用 &lt;%。因此,要在这两种情况下获得预期的行为,请使用以下语法:

    <%= test_h1 do %>
      <%= 'test1' %>
    <% end -%>
    
    <%= test_h2 do %>
      <% 'test2' %>
    <% end -%>
    

    本文中的更多信息:https://thepugautomatic.com/2013/06/helpers/

    【讨论】:

    • (a) 我可能有&lt;%= test_h2 do %&gt;&lt;span&gt;...&lt;/span&gt;&lt;% end %&gt;,在这种情况下&lt;span/&gt; 将在&lt;a&gt;&lt;/a&gt; 之外; (b) 这背后的逻辑是什么?为什么控制器辅助方法以这种方式工作?为什么它对帮助模块按预期工作?
    • capture 正在将“捕获”的内容立即推送到页面缓冲区。因此,“捕获”和“输出”的所有内容(例如原始 html 或 &lt;%= erb 标签中的内容) 将在执行您的 `test_h2̀ 方法之前呈现,这就是为什么在 标记之前呈现 'test2' 的原因。
    【解决方案4】:

    在 Rails 中执行此操作的惯用方法是将 test_h2 方法移至关注点,并将该关注点包含在控制器和帮助程序类中。

    或者在控制器类中将 test_h2 定义为 helper_method。

    但一般来说,在多个地方需要的方法应该放在关注点中,并在需要的地方包含这些关注点。

    此外,如果您需要视图方法,请在帮助程序中包含关注点或定义您自己的方法。

    参考Can we call a Controller's method from a view (as we call from helper ideally)?
    How to use concerns in Rails 4

    【讨论】:

    • 在您的控制器中使用 helper_method :test_h2 作为解决方法。但据我所知,惯用的方式会引起关注。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    • 2018-02-07
    • 2010-11-07
    • 1970-01-01
    • 2016-05-28
    相关资源
    最近更新 更多