класс 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_counter. В случае примера выше, шаблон получит ad_counter.
Параметр :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" %>
ПРИМЕЧАНИЕ: Из-за проблем обратной совместимости коллекция не может быть массивом хешей. Обычно вы также просто сохраняете объекты домена, такие как Active Records, в нём.
Отображение общих частичных представлений
Два контроллера могут совместно использовать набор частичных представлений и отобразить их так:
<%= 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 256 def initialize(*) super @context_prefix = @lookup_context.prefixes.first end
Публичные методы экземпляра
# File actionview/lib/action_view/renderer/partial_renderer.rb, line 261
def render(context, options, block)
setup(context, options, block)
identifier = (@template = find_partial) ? @template.identifier : @path
@lookup_context.rendered_format ||= begin
if @template && @template.formats.present?
@template.formats.first
else
formats.first
end
end
if @collection
instrument(:collection, :identifier => identifier || "collection", :count => @collection.size) do
render_collection
end
else
instrument(:partial, :identifier => identifier) do
render_partial
end
end
end # File actionview/lib/action_view/renderer/partial_renderer.rb, line 284
def render_collection
return nil if @collection.blank?
if @options.key?(:spacer_template)
spacer = find_template(@options[:spacer_template], @locals.keys).render(@view, @locals)
end
result = @template ? collection_with_template : collection_without_template
result.join(spacer).html_safe
end # File actionview/lib/action_view/renderer/partial_renderer.rb, line 295
def render_partial
view, locals, block = @view, @locals, @block
object, as = @object, @variable
if !block && (layout = @options[:layout])
layout = find_template(layout.to_s, @template_keys)
end
object ||= locals[as]
locals[as] = object
content = @template.render(view, locals) do |*name|
view._layout_for(*name, &block)
end
content = layout.render(view, locals){ content } if layout
content
end
© 2004–2016 David Heinemeier Hansson
Licensed under the MIT License.