класс 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 между каждым частичным представлением объявления:
<%= 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 %> Рендеринг по умолчанию
Если вы не будете использовать какие-либо параметры, такие как коллекции или макеты, вы также можете использовать сокращённые значения по умолчанию для рендеринга частичных представлений. Примеры:
# 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> Текущий рендеринг объект, а также объект_счётчик, будут доступны в шаблоне макета в качестве локальных переменных под теми же именами, что и в частичном представлении.
Вы также можете применить макет к блоку в любом шаблоне:
<%# 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
- ИМЕНА_ЧАСТИЧНЫХ_ПРЕДСТАВЛЕНИЙ_С_ПРЕФИКСОМ
Публичные методы класса
# File actionview/lib/action_view/renderer/partial_renderer.rb, line 289 def initialize(*) super @context_prefix = @lookup_context.prefixes.first end
Публичные методы экземпляра
# File actionview/lib/action_view/renderer/partial_renderer.rb, line 294
def render(context, options, block)
as = as_variable(options)
setup(context, options, as, block)
if @path
if @has_object || @collection
@variable, @variable_counter, @variable_iteration = retrieve_variable(@path, as)
@template_keys = retrieve_template_keys(@variable)
else
@template_keys = @locals.keys
end
template = find_partial(@path, @template_keys)
@variable ||= template.variable
else
if options[:cached]
raise NotImplementedError, "render caching requires a template. Please specify a partial when rendering"
end
template = nil
end
if @collection
render_collection(context, template)
else
render_partial(context, template)
end
end
© 2004–2019 David Heinemeier Hansson
Licensed under the MIT License.