跳至内容 跳至搜索

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

如果给定的:collectionnil 或为空,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 的对象

您无需显式命名部分的位置,也可以让 PartialRenderer 通过检查to_partial_path 方法来完成工作并选择正确的路径。

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

渲染默认情况

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

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

当前正在渲染的对象以及对象计数器将作为局部变量在布局模板中以与部分中可用的相同名称提供。

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

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