class ActionView::PartialRenderer

<% end %>
<%- end -%>
Deadline: <%= user.deadline %>
<%- when :footer -%>
Title: <%= user.title %>
<%- case section when :header -%>
<%= render layout: @users do |user, section| %>
<%# app/views/users/index.html.erb %>
</div>
<%= yield user, :footer %>
Budget: $<%= user.budget %>
<%= yield user, :header %>
<div class=“user”>
<%# app/views/users/_user.html.erb %>
You can also yield multiple times in one layout and use block arguments to differentiate the sections.
This will render the layout for each user and yield to the block, passing the user, each time.
<% end %>
Title: <%= user.title %>
<%= render layout: @users do |user| %>
<%# app/views/users/index.html.erb %>
</div>
<%= yield user %>
Budget: $<%= user.budget %>
<div class=“user”>
<%# app/views/users/_user.html.erb %>
an array to layout and treat it as an enumerable.
If you pass arguments to “yield” then this will be passed to the block. One way to use this is to pass
As you can see, the :locals hash is shared between both the partial and its layout.
</div>
Title: <%= chief.name %>
Budget: $<%= user.budget %>
<div id=“administrator”>
…this will return:
<% end %>
Title: <%= chief.title %>
<%= render(layout: “administrator”, locals: { user: chief }) do %>
<%# app/views/users/_chief.html.erb %>
You can also apply a layout to a block within any template:
as available in the partial.
available as local variables inside the layout template under the same names
The current object being rendered, as well as the object_counter, will be
</ul>
</li>
Name: Bob
<li>
</li>
Name: Alice
<li>
<ul>
Given two users whose names are Alice and Bob, these snippets return:
</ul>
<%= render partial: “user”, layout: “li_layout”, collection: users %>
<ul>
<%# app/views/users/index.html.erb %>
</li>
<%= yield %>
<li>
<%# app/views/users/_li_layout.html.erb %>
</ul>
<% end -%>
</li>
<%= render partial: “user”, locals: { user: user } %>
<li>
<% users.each do |user| -%>
<ul>
<%# This does not use layouts %>
<%# app/views/users/index.html.erb %>
Name: <%= user.name %>
<%# app/views/users/_user.html.erb %>
the collection. For example, these two snippets have the same output:
If a collection is given, the layout will be rendered once for each item in
</div>
Name: <%= user.name %>
Deadline: <%= user.deadline %>
<div id=“editor”>
Here’s the editor:
</div>
Name: <%= user.name %>
Budget: $<%= user.budget %>
<div id=“administrator”>
Here’s the administrator:
…this will return:
</div>
<%= yield %>
Deadline: <%= user.deadline %>
<div id=“editor”>
<%# app/views/users/_editor.html.erb %>
</div>
<%= yield %>
Budget: $<%= user.budget %>
<div id=“administrator”>
<%# app/views/users/_administrator.html.erb %>
Name: <%= user.name %>
<%# app/views/users/_user.html.erb %>
<%= render partial: “user”, layout: “editor”, locals: { user: editor } %>
Here’s the editor:
<%= render partial: “user”, layout: “administrator”, locals: { user: administrator } %>
Here’s the administrator:
<%# app/views/users/index.html.erb %>
of users:
specified globally for the entire action, but they work in a similar fashion. Imagine a list with two types
Partials can have their own layouts applied to them. These layouts are different than the ones that are
== Rendering partials with layouts
<%= render @posts %>
# <%= render partial: “posts/post”, collection: @posts %>
# that’s why we can replace:
# @posts is an array of Post instances, so every post record returns ‘posts/post’ on ‘to_partial_path`,
<%= render @account %>
# <%= render partial: “accounts/account”, locals: { account: @account} %>
# @account.to_partial_path returns ’accounts/account’, so it can be used to replace:
<%= render “account”, account: @buyer %>
# Instead of <%= render partial: “account”, locals: { account: @buyer } %>
<%= render “account” %>
# Instead of <%= render partial: “account” %>
defaults of render to render partials. Examples:
If you’re not going to be using any of the options like collections or layouts, you can also use the short-hand
== Rendering the default case
<%= render partial: @posts %>
# <%= render partial: “posts/post”, collection: @posts %>
# that’s why we can replace:
# @posts is an array of Post instances, so every post record returns ‘posts/post’ on ‘to_partial_path`,
<%= render partial: @account %>
# <%= render partial: “accounts/account”, locals: { account: @account} %>
# @account.to_partial_path returns ’accounts/account’, so it can be used to replace:
and pick the proper path by checking ‘to_partial_path` method.
Instead of explicitly naming the location of a partial, you can also let PartialRenderer do the work
== Rendering objects that respond to `to_partial_path`
This will render the partial “advertisement/_ad.html.erb” regardless of which controller this is being called from.
<%= render partial: “advertisement/ad”, locals: { ad: @advertisement } %>
Two controllers can share a set of partials and render them like this:
== Rendering shared partials
just keep domain objects, like Active Records, in there.
NOTE: Due to backwards compatibility concerns, the collection can’t be one of hashes. Normally you’d also
<%= render(partial: “ad”, collection: @advertisements) || “There’s no ad to be displayed” %>
to specify a text which will displayed instead by using this form:
If the given :collection is nil or empty, render will return nil. This will allow you
<%= render partial: “ad”, collection: @advertisements, spacer_template: “ad_divider” %>
The following example will render advertiser/_ad_divider.html.erb between each ad partial:
You can specify a partial to be rendered between elements via the :spacer_template option.
The :as option may be used when rendering partials.
index method.
For backwards compatibility the partial_name_counter is still present and is mapped to the iteration’s
first? and last?. In the case of the example above, the template would be fed ad_iteration.
the collection and the total size of the collection. The iteration object also has two convenience methods,
partial_name_iteration. The iteration object has knowledge about which index the current object has in
iteration object will automatically be made available to the template with a name of the form
This will render “advertiser/_ad.html.erb” and pass the local variable ad to the template for display. An
<%= render partial: “ad”, collection: @advertisements %>
example in “Using partials” can be rewritten with a single line:
accepts an array and renders a partial by the same name as the elements contained within. So the three-lined
render a sub template for each of the elements. This pattern has been implemented as a single method that
The example of partial use describes a familiar pattern where a template needs to iterate over an array and
== Rendering a collection of partials
<%= render partial: “account”, locals: { user: @buyer } %>
This is equivalent to
<%= render partial: “account”, object: @buyer, as: ‘user’ %>
wanted it to be user instead of account we’d do:
With the :as option we can specify a different name for said local variable. For example, if we
<%= render partial: “account”, locals: { account: @buyer } %>
equivalent to:
would provide the @buyer object to the partial, available under the local variable account and is
<%= render partial: “account”, object: @buyer %>
The :object option can be used to pass an object to the partial. For instance:
By default ActionView::PartialRenderer doesn’t have any local variables.
== The :as and :object options
render “advertiser/_ad.html.erb” and pass the local variable ad to the template for display.
This would first render “advertiser/_account.html.erb” with @buyer passed in as the local variable account, then
<% end %>
<%= render partial: “ad”, locals: { ad: ad } %>
<% @advertisements.each do |ad| %>
<%= render partial: “account”, locals: { account: @buyer } %>
In another template for Advertiser#buy, we could have:
This would render “advertiser/_account.html.erb”.
<%= render partial: “account” %>
In a template for Advertiser#account:
templates that could be rendered on their own.
follow the naming convention of being prefixed with an underscore – as to separate them from regular
single object (we call this kind of sub templates for partials). It relies on the fact that partials should
There’s also a convenience method for rendering sub templates within the current controller that depends on a
= Action View Partials

def collection_from_object

def collection_from_object
  @object.to_ary if @object.respond_to?(:to_ary)
end

def collection_from_options

def collection_from_options
  if @options.key?(:collection)
    collection = @options[:collection]
    collection.respond_to?(:to_ary) ? collection.to_ary : []
  end
end

def collection_with_template

def collection_with_template
  view, locals, template = @view, @locals, @template
  as, counter, iteration = @variable, @variable_counter, @variable_iteration
  if layout = @options[:layout]
    layout = find_template(layout, @template_keys)
  end
  partial_iteration = PartialIteration.new(@collection.size)
  locals[iteration] = partial_iteration
  @collection.map do |object|
    locals[as]        = object
    locals[counter]   = partial_iteration.index
    content = template.render(view, locals)
    content = layout.render(view, locals) { content } if layout
    partial_iteration.iterate!
    content
  end
end

def collection_without_template

def collection_without_template
  view, locals, collection_data = @view, @locals, @collection_data
  cache = {}
  keys  = @locals.keys
  partial_iteration = PartialIteration.new(@collection.size)
  @collection.map do |object|
    index = partial_iteration.index
    path, as, counter, iteration = collection_data[index]
    locals[as]        = object
    locals[counter]   = index
    locals[iteration] = partial_iteration
    template = (cache[path] ||= find_template(path, keys + [as, counter]))
    content = template.render(view, locals)
    partial_iteration.iterate!
    content
  end
end

def find_partial

def find_partial
  find_template(@path, @template_keys) if @path
end

def find_template(path, locals)

def find_template(path, locals)
  prefixes = path.include?(?/) ? [] : @lookup_context.prefixes
  @lookup_context.find_template(path, prefixes, true, locals, @details)
end

def initialize(*)

def initialize(*)
  super
  @context_prefix = @lookup_context.prefixes.first
end

def merge_prefix_into_object_path(prefix, object_path)

def merge_prefix_into_object_path(prefix, object_path)
  if prefix.include?(?/) && object_path.include?(?/)
    prefixes = []
    prefix_array = File.dirname(prefix).split('/')
    object_path_array = object_path.split('/')[0..-3] # skip model dir & partial
    prefix_array.each_with_index do |dir, index|
      break if dir == object_path_array[index]
      prefixes << dir
    end
    (prefixes << object_path).join("/")
  else
    object_path
  end
end

def partial_path(object = @object)

method will prefix the partial paths with a namespace.
If +prefix_partial_path_with_controller_namespace+ is true, then this

then an +ArgumentError+ is raised.
will provide the path. If the object does not respond to +to_partial_path+,
responds to +to_partial_path+, then +to_partial_path+ will be called and
Obtains the path to where the object's partial is located. If the object
def partial_path(object = @object)
  object = object.to_model if object.respond_to?(:to_model)
  path = if object.respond_to?(:to_partial_path)
    object.to_partial_path
  else
    raise ArgumentError.new("'#{object.inspect}' is not an ActiveModel-compatible object. It must implement :to_partial_path.")
  end
  if @view.prefix_partial_path_with_controller_namespace
    prefixed_partial_names[path] ||= merge_prefix_into_object_path(@context_prefix, path.dup)
  else
    path
  end
end

def prefixed_partial_names

def prefixed_partial_names
  @prefixed_partial_names ||= PREFIXED_PARTIAL_NAMES[@context_prefix]
end

def raise_invalid_identifier(path)

def raise_invalid_identifier(path)
  raise ArgumentError.new(IDENTIFIER_ERROR_MESSAGE % (path))
end

def raise_invalid_option_as(as)

def raise_invalid_option_as(as)
  raise ArgumentError.new(OPTION_AS_ERROR_MESSAGE % (as))
end

def render(context, options, block)

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

def render_collection

def render_collection
  instrument(:collection, count: @collection.size) do |payload|
    return nil if @collection.blank?
    if @options.key?(:spacer_template)
      spacer = find_template(@options[:spacer_template], @locals.keys).render(@view, @locals)
    end
    cache_collection_render(payload) do
      @template ? collection_with_template : collection_without_template
    end.join(spacer).html_safe
  end
end

def render_partial

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] if object.nil? # Respect object when object is false
  locals[as] = object if @has_object
  content = @template.render(view, locals) do |*name|
    view._layout_for(*name, &block)
  end
  content = layout.render(view, locals){ content } if layout
  content
end

def retrieve_template_keys

def retrieve_template_keys
  keys = @locals.keys
  keys << @variable if @has_object || @collection
  if @collection
    keys << @variable_counter
    keys << @variable_iteration
  end
  keys
end

def retrieve_variable(path, as)

def retrieve_variable(path, as)
  variable = as || begin
    base = path[-1] == "/".freeze ? "".freeze : File.basename(path)
    raise_invalid_identifier(path) unless base =~ /\A_?(.*?)(?:\.\w+)*\z/
    $1.to_sym
  end
  if @collection
    variable_counter = :"#{variable}_counter"
    variable_iteration = :"#{variable}_iteration"
  end
  [variable, variable_counter, variable_iteration]
end

def setup(context, options, block)

respond to +to_partial_path+ in order to setup the path.
set to that string. Otherwise, the +options[:partial]+ object must
If +options[:partial]+ is a string, then the +@path+ instance variable is

logic that handles the type of object passed in as the partial.
finds the options and details and extracts them. The method also contains
Sets up instance variables needed for rendering a partial. This method
def setup(context, options, block)
  @view   = context
  @options = options
  @block   = block
  @locals  = options[:locals] || {}
  @details = extract_details(options)
  prepend_formats(options[:formats])
  partial = options[:partial]
  if String === partial
    @has_object = options.key?(:object)
    @object     = options[:object]
    @collection = collection_from_options
    @path       = partial
  else
    @has_object = true
    @object = partial
    @collection = collection_from_object || collection_from_options
    if @collection
      paths = @collection_data = @collection.map { |o| partial_path(o) }
      @path = paths.uniq.one? ? paths.first : nil
    else
      @path = partial_path
    end
  end
  if as = options[:as]
    raise_invalid_option_as(as) unless as.to_s =~ /\A[a-z_]\w*\z/
    as = as.to_sym
  end
  if @path
    @variable, @variable_counter, @variable_iteration = retrieve_variable(@path, as)
    @template_keys = retrieve_template_keys
  else
    paths.map! { |path| retrieve_variable(path, as).unshift(path) }
  end
  self
end