класс 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» с @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 между каждым частичным шаблоном ad:
<%= render partial: "ad", collection: @advertisements, spacer_template: "ad_divider" %>
Если переданный :collection равен null или пуст, render вернёт null. Это позволит вам указать текст, который будет отображаться вместо него, используя такой формат:
<%= render(partial: "ad", collection: @advertisements) || "There's no ad to be displayed" %>
ПРИМЕЧАНИЕ: Из-за проблем с обратной совместимостью коллекция не может быть массивом хешей. Обычно вы бы хранили только объекты домена, такие как Active Record, в ней.
Рендеринг общих частичных шаблонов
Два контроллера могут использовать набор общих частичных шаблонов и рендерить их так:
<%= 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> Учитывая двух пользователей, чьи имена Алиса и Боб, эти фрагменты возвращают:
<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 делится между частичным шаблоном и его макетом.
Если вы передаёте аргументы в «yield», то они будут переданы в блок. Один способ использования этого — передать массив в макет и обработать его как перечислимый.
<%# app/views/users/_user.html.erb %> <div class="user"> Budget: $<%= user.budget %> <%= yield user %> </div> <%# app/views/users/index.html.erb %> <%= render layout: @users do |user| %> Title: <%= user.title %> <% end %>
Это рендерит макет для каждого пользователя и передаёт в блок, каждый раз передавая пользователя.
Вы также можете вызывать yield несколько раз в одном макете и использовать аргументы блока, чтобы различать секции.
<%# app/views/users/_user.html.erb %>
<div class="user">
<%= yield user, :header %>
Budget: $<%= user.budget %>
<%= yield user, :footer %>
</div>
<%# app/views/users/index.html.erb %>
<%= render layout: @users do |user, section| %>
<%- case section when :header -%>
Title: <%= user.title %>
<%- when :footer -%>
Deadline: <%= user.deadline %>
<%- end -%>
<% end %> Константы
- IDENTIFIER_ERROR_MESSAGE
- OPTION_AS_ERROR_MESSAGE
- PREFIXED_PARTIAL_NAMES
Публичные методы класса
# File actionview/lib/action_view/renderer/partial_renderer.rb, line 290 def initialize(*) super @context_prefix = @lookup_context.prefixes.first end
Публичные методы экземпляра
# File actionview/lib/action_view/renderer/partial_renderer.rb, line 295
def render(context, options, block)
setup(context, options, block)
@template = find_partial
@lookup_context.rendered_format ||= begin
if @template && @template.formats.present?
@template.formats.first
else
formats.first
end
end
if @collection
render_collection
else
instrument(:partial) do
render_partial
end
end
end
© 2004–2018 David Heinemeier Hansson
Licensed under the MIT License.