class ActionView::PartialRenderer
Частичные шаблоны 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, которому в качестве локальной переменной account будет передан @buyer, а затем отобразится advertiser/_ad.html.erb, которому будет передана локальная переменная ad для отображения в шаблоне.
Параметры :as и :object
По умолчанию ActionView::PartialRenderer не имеет локальных переменных. Параметр :object можно использовать для передачи объекта частичному шаблону. Например:
<%= render partial: "account", object: @buyer %>
объект @buyer будет передан частичному шаблону и доступен в локальной переменной account. Это эквивалентно следующему:
<%= render partial: "account", locals: { account: @buyer } %> С помощью параметра :as можно указать другое имя для этой локальной переменной. Например, если вместо account мы хотим использовать user, то напишем:
<%= render partial: "account", object: @buyer, as: 'user' %>
Это эквивалентно следующему:
<%= render partial: "account", locals: { user: @buyer } %> Отображение вариантов частичного шаблона
Параметр :variants можно использовать для отображения другого варианта шаблона частичного шаблона. Например:
<%= render partial: "account", variants: :mobile %>
Будет отображён _account.html+mobile.erb. Этот параметр также принимает несколько вариантов, например:
<%= render partial: "account", variants: [:desktop, :mobile] %>
Будут проверены следующие шаблоны, и отобразится первый из существующих:
-
_account.html+desktop.erb -
_account.html+mobile.erb -
_account.html.erb
Отображение коллекции частичных шаблонов
В примере использования частичных шаблонов описан знакомый шаблон, в котором шаблону нужно перебрать массив и отобразить подшаблон для каждого элемента. Этот шаблон реализован в виде единственного метода, который принимает массив и отображает частичный шаблон с тем же именем, что и у содержащихся в массиве элементов. Таким образом, трёхстрочный пример из раздела «Использование частичных шаблонов» можно переписать одной строкой:
<%= 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
Вместо явного указания расположения частичного шаблона можно поручить 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 общий для частичного шаблона и его макета.
Открытые методы класса
# File actionview/lib/action_view/renderer/partial_renderer.rb, line 239
def initialize(lookup_context, options)
super(lookup_context)
@options = options
@locals = @options[:locals] || {}
@details = extract_details(@options)
end Открытые методы экземпляра
# File actionview/lib/action_view/renderer/partial_renderer.rb, line 246
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
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.