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
<%= render(partial: “ad”, collection: @advertisements) || “There’s no ad to be displayed” %>
to specify a text which will be 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 as_variable(options)

def as_variable(options)
  if as = options[:as]
    raise_invalid_option_as(as) unless /\A[a-z_]\w*\z/.match?(as.to_s)
    as.to_sym
  end
end

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 ? collection.to_a : []
  end
end

def collection_with_template(view, template)

def collection_with_template(view, template)
  locals = @locals
  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!
    build_rendered_template(content, template, layout)
  end
end

def collection_without_template(view)

def collection_without_template(view)
  locals, collection_data = @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, iteration]))
    content = template.render(view, locals)
    partial_iteration.iterate!
    build_rendered_template(content, template)
  end
end

def find_partial(path, template_keys)

def find_partial(path, template_keys)
  find_template(path, template_keys)
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, view)

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, view)
  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)
  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

def render_collection(view, template)

def render_collection(view, template)
  identifier = (template && template.identifier) || @path
  instrument(:collection, identifier: identifier, count: @collection.size) do |payload|
    return RenderedCollection.empty(@lookup_context.formats.first) if @collection.blank?
    spacer = if @options.key?(:spacer_template)
      spacer_template = find_template(@options[:spacer_template], @locals.keys)
      build_rendered_template(spacer_template.render(view, @locals), spacer_template)
    else
      RenderedTemplate::EMPTY_SPACER
    end
    collection_body = if template
      cache_collection_render(payload, view, template) do
        collection_with_template(view, template)
      end
    else
      collection_without_template(view)
    end
    build_rendered_collection(collection_body, spacer)
  end
end

def render_partial(view, template)

def render_partial(view, template)
  instrument(:partial, identifier: template.identifier) do |payload|
    locals, block = @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
    payload[:cache_hit] = view.view_renderer.cache_hits[template.virtual_path]
    build_rendered_template(content, template, layout)
  end
end

def retrieve_template_keys(variable)

def retrieve_template_keys(variable)
  keys = @locals.keys
  keys << variable
  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] == "/" ? "" : 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, as, 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, as, block)
  @options = options
  @block   = block
  @locals  = options[:locals] || {}
  @details = extract_details(options)
  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, context) }
      if paths.uniq.length == 1
        @path = paths.first
      else
        paths.map! { |path| retrieve_variable(path, as).unshift(path) }
        @path = nil
      end
    else
      @path = partial_path(@object, context)
    end
  end
  self
end