跳到內文 跳到搜尋

Action 視圖部分

還有一個方便的方法可以在當前控制器中呈現子範本,它取決於單一物件(我們稱這種子範本為部分)。它依賴於部分應該遵循命名前綴為底線的命名慣例,以將它們與可以自行呈現的常規範本區分開。

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

這會先使用傳入的 @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 %>

呈現預設情況

如果你不打算使用任何集合或版面選項,也可以使用簡寫的 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