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:
</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:
all objects must return the same path.
and pick the proper path by checking ‘to_proper_path` method. If the object passed to render is a collection,
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.
partial_name_counter. In the case of the example above, the template would be fed ad_counter.
iteration counter 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

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

def collection_from_object

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

def collection_with_template

def collection_with_template
  segments, locals, template = [], @locals, @template
  as, counter = @variable, @variable_counter
  locals[counter] = -1
  @collection.each do |object|
    locals[counter] += 1
    locals[as] = object
    segments << template.render(@view, locals)
  end
  segments
end

def collection_without_template

def collection_without_template
  segments, locals, collection_data = [], @locals, @collection_data
  index, template, cache = -1, nil, {}
  keys = @locals.keys
  @collection.each_with_index do |object, i|
    path, *data = collection_data[i]
    template = (cache[path] ||= find_template(path, keys + data))
    locals[data[0]] = object
    locals[data[1]] = (index += 1)
    segments << template.render(@view, locals)
  end
  @template = template
  segments
end

def find_partial

def find_partial
  if path = @path
    locals = @locals.keys
    locals << @variable
    locals << @variable_counter if @collection
    find_template(path, locals)
  end
end

def find_template(path=@path, locals=@locals.keys)

def find_template(path=@path, locals=@locals.keys)
  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
  @partial_names = PARTIAL_NAMES[@context_prefix]
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)

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
    klass = object.class
    if klass.respond_to?(:model_name)
      ActiveSupport::Deprecation.warn "ActiveModel-compatible objects whose classes return a #model_name that responds to #partial_path are deprecated. Please respond to #to_partial_path directly instead."
      klass.model_name.partial_path
    else
      raise ArgumentError.new("'#{object.inspect}' is not an ActiveModel-compatible object that returns a valid partial path.")
    end
  end
  @partial_names[path] ||= merge_prefix_into_object_path(@context_prefix, path.dup)
end

def render(context, options, block)

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

def render_collection

def render_collection
  return nil if @collection.blank?
  if @options.key?(:spacer_template)
    spacer = find_template(@options[:spacer_template]).render(@view, @locals)
  end
  result = @template ? collection_with_template : collection_without_template
  result.join(spacer).html_safe
end

def render_partial

def render_partial
  locals, view, block = @locals, @view, @block
  object, as = @object, @variable
  if !block && (layout = @options[:layout])
    layout = find_template(layout)
  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

def retrieve_variable(path)

def retrieve_variable(path)
  variable = @options.fetch(:as) { path[%r'_?(\w+)(\.\w+)*$', 1] }.try(:to_sym)
  variable_counter = :"#{variable}_counter" if @collection
  [variable, variable_counter]
end

def setup(context, options, block)

def setup(context, options, block)
  @view   = context
  partial = options[:partial]
  @options = options
  @locals  = options[:locals] || {}
  @block   = block
  @details = extract_details(options)
  if String === partial
    @object     = options[:object]
    @path       = partial
    @collection = collection
  else
    @object = partial
    if @collection = collection_from_object || collection
      paths = @collection_data = @collection.map { |o| partial_path(o) }
      @path = paths.uniq.size == 1 ? paths.first : nil
    else
      @path = partial_path
    end
  end
  if @path
    @variable, @variable_counter = retrieve_variable(@path)
  else
    paths.map! { |path| retrieve_variable(path).unshift(path) }
  end
  if String === partial && @variable.to_s !~ /^[a-z_][a-zA-Z_0-9]*$/
    raise ArgumentError.new("The partial name (#{partial}) is not a valid Ruby identifier; " +
                            "make sure your partial name starts with a letter or underscore, " +
                            "and is followed by any combinations of letters, numbers, or underscores.")
  end
  extract_format(@path, @details)
  self
end