跳至内容 跳至搜索

Action View 捕获帮助器

CaptureHelper 公开方法,让你可以提取生成的标记,这些标记可以在模板或布局文件的其他部分使用。

它提供了一种通过 capture 将块捕获到变量中的方法,以及通过 content_for 捕获块标记以在布局中使用的方法。

当通过 provide 使用流响应时,还提供了一种方法。有关更多信息,请参阅 ActionController::Streaming

方法
C
P

实例公共方法

capture(*args, &block)

capture 方法将模板的一部分作为字符串对象提取出来。然后,你可以在模板、布局或帮助器中的任何位置使用此对象。

capture 方法可以在 ERB 模板中使用…

<% @greeting = capture do %>
  Welcome to my shiny new web page!  The date and time is
  <%= Time.now %>
<% end %>

…和 Builder (RXML) 模板。

@timestamp = capture do
  "The current timestamp is #{Time.now}."
end

然后,你可以在任何其他位置使用该变量。例如

<html>
<head><title><%= @greeting %></title></head>
<body>
<b><%= @greeting %></b>
</body>
</html>

capture 的返回值是由块生成的字符串。例如

@greeting # => "Welcome to my shiny new web page! The date and time is 2018-09-06 11:09:16 -0500"
# File actionview/lib/action_view/helpers/capture_helper.rb, line 47
def capture(*args, &block)
  value = nil
  @output_buffer ||= ActionView::OutputBuffer.new
  buffer = @output_buffer.capture { value = yield(*args) }

  string = if @output_buffer.equal?(value)
    buffer
  else
    buffer.presence || value
  end

  case string
  when OutputBuffer
    string.to_s
  when ActiveSupport::SafeBuffer
    string
  when String
    ERB::Util.html_escape(string)
  end
end

content_for(name, content = nil, options = {}, &block)

调用 content_for 会将块标记存储在标识符中以供以后使用。为了在其他模板、帮助器模块或布局中访问此存储的内容,你需要将标识符作为参数传递给 content_for

注意:yield 仍然可以用来检索存储的内容,但调用 yield 在帮助器模块中不起作用,而 content_for 起作用。

<% content_for :not_authorized do %>
  alert('You are not authorized to do that!')
<% end %>

然后,你可以在模板中的任何位置使用 content_for :not_authorized

<%= content_for :not_authorized if current_user.nil? %>

这相当于

<%= yield :not_authorized if current_user.nil? %>

但是,content_for 也可以在帮助器模块中使用。

module StorageHelper
  def stored_content
    content_for(:storage) || "Your storage is empty"
  end
end

此帮助器的工作方式与普通帮助器相同。

<%= stored_content %>

您还可以在布局中使用 yield 语法和对 yield 的现有调用。例如

<%# This is the layout %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>My Website</title>
  <%= yield :script %>
</head>
<body>
  <%= yield %>
</body>
</html>

现在,我们将创建一个具有 content_for 调用(创建 script 标识符)的视图。

<%# This is our view %>
Please login!

<% content_for :script do %>
  <script>alert('You are not authorized to view this page!')</script>
<% end %>

然后,在另一个视图中,您可以执行类似以下操作

<%= link_to 'Logout', action: 'logout', remote: true %>

<% content_for :script do %>
  <%= javascript_include_tag :defaults %>
<% end %>

这将在页面上放置您的默认 JavaScript 文件集的 script 标签;如果您只在几个视图中使用这些脚本,此技术很有用。

请注意,content_for 按顺序连接(默认)为特定标识符提供的块。例如

<% content_for :navigation do %>
  <li><%= link_to 'Home', action: 'index' %></li>
<% end %>

在另一个地方

<% content_for :navigation do %>
  <li><%= link_to 'Login', action: 'login' %></li>
<% end %>

然后,在另一个模板或布局中,此代码将按顺序呈现这两个链接

<ul><%= content_for :navigation %></ul>

如果 flush 参数为 truecontent_for 将替换它所给出的块。例如

<% content_for :navigation do %>
  <li><%= link_to 'Home', action: 'index' %></li>
<% end %>

<%# Add some other content, or use a different template: %>

<% content_for :navigation, flush: true do %>
  <li><%= link_to 'Login', action: 'login' %></li>
<% end %>

然后,在另一个模板或布局中,此代码将只呈现最后一个链接

<ul><%= content_for :navigation %></ul>

最后,可以将简单内容作为参数传递

<% content_for :script, javascript_include_tag(:defaults) %>

警告:content_for 在缓存中被忽略。因此,您不应将其用于将被片段缓存的元素。

# File actionview/lib/action_view/helpers/capture_helper.rb, line 172
def content_for(name, content = nil, options = {}, &block)
  if content || block_given?
    if block_given?
      options = content if content
      content = capture(&block)
    end
    if content
      options[:flush] ? @view_flow.set(name, content) : @view_flow.append(name, content)
    end
    nil
  else
    @view_flow.get(name).presence
  end
end

content_for?(name)

content_for? 检查是否已使用 content_for 捕获任何内容。

根据视图中的内容以不同的方式呈现布局的各个部分非常有用。

<%# This is the layout %>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>My Website</title>
  <%= yield :script %>
</head>
<body class="<%= content_for?(:right_col) ? 'two-column' : 'one-column' %>">
  <%= yield %>
  <%= yield :right_col %>
</body>
</html>
# File actionview/lib/action_view/helpers/capture_helper.rb, line 215
def content_for?(name)
  @view_flow.get(name).present?
end

provide(name, content = nil, &block)

content_for 相同,但与流媒体一起使用时会直接刷新回布局。换句话说,如果您想在呈现给定模板时多次连接到同一个缓冲区,则应使用 content_for,如果不是,则使用 provide 告诉布局停止查找更多内容。

有关更多信息,请参阅 ActionController::Streaming

# File actionview/lib/action_view/helpers/capture_helper.rb, line 194
def provide(name, content = nil, &block)
  content = capture(&block) if block_given?
  result = @view_flow.append!(name, content) if content
  result unless content
end