跳至内容 跳至搜索

Action View 部分

还有一种方便的方法可以在当前控制器中渲染子模板,该方法依赖于单个对象(我们将这种子模板称为部分)。它依赖于这样一个事实,即部分应该遵循以下划线为前缀的命名约定,以将它们与可以单独渲染的常规模板区分开来。

在 Advertiser#account 的模板中

<%= render partial: "account" %>

这将渲染“advertiser/_account.html.erb”。

在 Advertiser#buy 的另一个模板中,我们可以有

<%= render partial: "account", locals: { account: @buyer } %>

<% @advertisements.each do |ad| %>
  <%= render partial: "ad", locals: { ad: ad } %>
<% end %>

这将首先渲染 advertiser/_account.html.erb,并将 @buyer 作为局部变量 account 传递,然后渲染 advertiser/_ad.html.erb 并将局部变量 ad 传递给模板以进行显示。

:as:object 选项

默认情况下,ActionView::PartialRenderer 没有任何局部变量。:object 选项可用于将对象传递给部分。例如

<%= render partial: "account", object: @buyer %>

@buyer 对象提供给部分,在局部变量 account 下可用,等效于

<%= render partial: "account", locals: { account: @buyer } %>

使用 :as 选项,我们可以为该局部变量指定不同的名称。例如,如果我们希望它为 user 而不是 account,我们可以这样做

<%= render partial: "account", object: @buyer, as: 'user' %>

这等效于

<%= render partial: "account", locals: { user: @buyer } %>

渲染部分集合

部分使用的示例描述了一种熟悉的模式,其中模板需要遍历数组并为每个元素渲染一个子模板。此模式已实现为一个单一方法,该方法接受一个数组并通过与其中包含的元素相同的名称渲染一个部分。因此,“使用部分”中的三行示例可以用一行重写

<%= render partial: "ad", collection: @advertisements %>

这将渲染 `advertiser/_ad.html.erb` 并将局部变量 `ad` 传递给模板以供显示。一个迭代对象将自动被提供给模板,其名称格式为 `partial_name_iteration`。迭代对象知道当前对象在集合中的索引以及集合的总大小。迭代对象还有两个便捷方法,`first?` 和 `last?`。在上面的示例中,模板将被提供 `ad_iteration`。为了向后兼容,`partial_name_counter` 仍然存在,并映射到迭代的 `index` 方法。

渲染局部模板时可以使用 `:as` 选项。

您可以通过 `:spacer_template` 选项指定在元素之间渲染的局部模板。以下示例将在每个广告局部模板之间渲染 `advertiser/_ad_divider.html.erb`

<%= render partial: "ad", collection: @advertisements, spacer_template: "ad_divider" %>

如果给定的 `:collection` 为 `nil` 或为空,`render` 将返回 `nil`。这将允许您使用此形式指定将显示的文本

<%= render(partial: "ad", collection: @advertisements) || "There's no ad to be displayed" %>

渲染共享局部模板

两个控制器可以共享一组局部模板并像这样渲染它们

<%= render partial: "advertisement/ad", locals: { ad: @advertisement } %>

这将渲染局部模板 `advertisement/_ad.html.erb`,无论调用此模板的是哪个控制器。

渲染响应 `to_partial_path` 的对象

您可以通过检查 `to_partial_path` 方法,让 PartialRenderer 来完成工作并选择正确的路径,而不是显式地命名局部模板的位置。

# @account.to_partial_path returns 'accounts/account', so it can be used to replace:
# <%= render partial: "accounts/account", locals: { account: @account} %>
<%= render partial: @account %>

# @posts is an array of Post instances, so every post record returns 'posts/post' on +to_partial_path+,
# that's why we can replace:
# <%= render partial: "posts/post", collection: @posts %>
<%= render partial: @posts %>

渲染默认情况

如果您不打算使用任何选项,例如集合或布局,您也可以使用 render 的简写默认值来渲染局部模板。示例

# Instead of <%= render partial: "account" %>
<%= render "account" %>

# Instead of <%= render partial: "account", locals: { account: @buyer } %>
<%= render "account", account: @buyer %>

# @account.to_partial_path returns 'accounts/account', so it can be used to replace:
# <%= render partial: "accounts/account", locals: { account: @account} %>
<%= render @account %>

# @posts is an array of Post instances, so every post record returns 'posts/post' on +to_partial_path+,
# that's why we can replace:
# <%= render partial: "posts/post", collection: @posts %>
<%= render @posts %>

使用布局渲染局部模板

局部模板可以应用自己的布局。这些布局不同于为整个操作全局指定的布局,但它们的工作方式类似。想象一个包含两种类型用户的列表

<%# app/views/users/index.html.erb %>
Here's the administrator:
<%= render partial: "user", layout: "administrator", locals: { user: administrator } %>

Here's the editor:
<%= render partial: "user", layout: "editor", locals: { user: editor } %>

<%# app/views/users/_user.html.erb %>
Name: <%= user.name %>

<%# app/views/users/_administrator.html.erb %>
<div id="administrator">
  Budget: $<%= user.budget %>
  <%= yield %>
</div>

<%# app/views/users/_editor.html.erb %>
<div id="editor">
  Deadline: <%= user.deadline %>
  <%= yield %>
</div>

…这将返回

Here's the administrator:
<div id="administrator">
  Budget: $<%= user.budget %>
  Name: <%= user.name %>
</div>

Here's the editor:
<div id="editor">
  Deadline: <%= user.deadline %>
  Name: <%= user.name %>
</div>

如果给定一个集合,布局将为集合中的每个项目渲染一次。例如,这两个代码段具有相同的输出

<%# app/views/users/_user.html.erb %>
Name: <%= user.name %>

<%# app/views/users/index.html.erb %>
<%# This does not use layouts %>
<ul>
  <% users.each do |user| -%>
    <li>
      <%= render partial: "user", locals: { user: user } %>
    </li>
  <% end -%>
</ul>

<%# app/views/users/_li_layout.html.erb %>
<li>
  <%= yield %>
</li>

<%# app/views/users/index.html.erb %>
<ul>
  <%= render partial: "user", layout: "li_layout", collection: users %>
</ul>

给定两个名为 Alice 和 Bob 的用户,这些代码段将返回

<ul>
  <li>
    Name: Alice
  </li>
  <li>
    Name: Bob
  </li>
</ul>

正在渲染的当前对象以及 object_counter 将作为局部变量在布局模板中可用,其名称与在局部模板中可用的一样。

您也可以将布局应用于任何模板中的块

<%# app/views/users/_chief.html.erb %>
<%= render(layout: "administrator", locals: { user: chief }) do %>
  Title: <%= chief.title %>
<% end %>

…这将返回

<div id="administrator">
  Budget: $<%= user.budget %>
  Title: <%= chief.name %>
</div>

如您所见,`:locals` 哈希在局部模板及其布局之间共享。

方法
N
R

类公共方法

new(lookup_context, options)

# File actionview/lib/action_view/renderer/partial_renderer.rb, line 223
def initialize(lookup_context, options)
  super(lookup_context)
  @options = options
  @locals  = @options[:locals] || {}
  @details = extract_details(@options)
end

实例公共方法

render(partial, context, block)

# File actionview/lib/action_view/renderer/partial_renderer.rb, line 230
def render(partial, context, block)
  template = find_template(partial, template_keys(partial))

  if !block && (layout = @options[:layout])
    layout = find_template(layout.to_s, template_keys(partial))
  end

  render_partial_template(context, @locals, template, layout, block)
end