123456789_123456789_123456789_123456789_123456789_

Class: ActionView::CollectionRenderer

Do not use. This class is for internal use only.
Relationships & Source Files
Namespace Children
Classes:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: ActionView::PartialRenderer
Defined in: actionview/lib/action_view/renderer/collection_renderer.rb

Constant Summary

AbstractRenderer - Inherited

NO_DETAILS

PartialRenderer - Inherited

EMPTY_PREFIXES

Class Attribute Summary

PartialRenderer - Inherited

.collection_cache

Fallback cache store if Action View is used without ::Rails.

Class Method Summary

PartialRenderer - Inherited

AbstractRenderer - Inherited

Instance Attribute Summary

Instance Method Summary

Constructor Details

This class inherits a constructor from ActionView::PartialRenderer

Instance Method Details

#collection_into_buffer(view, template, collection, spacer, &block) (private)

[ GitHub ]

  
# File 'actionview/lib/action_view/renderer/collection_renderer.rb', line 200

def collection_into_buffer(view, template, collection, spacer, &block)
  locals = @locals
  cache = {}
  spacer_body = spacer.body

  partial_iteration = PartialIteration.new(collection.size)
  buffer = nil
  first_template = nil

  collection.each_with_info do |object, (path, as, counter, iteration)|
    index = partial_iteration.index

    locals[as]        = object
    locals[counter]   = index
    locals[iteration] = partial_iteration

    _template, implicit_locals = (cache[path] ||= [template || find_template(path, @locals.keys + [as, counter, iteration]), [counter, iteration]])

    if buffer
      buffer.safe_concat(spacer_body) unless spacer_body.empty?
    else
      buffer = OutputBuffer.new
      first_template = _template
    end

    _template.render(view, locals, buffer, implicit_locals: implicit_locals, &block)
    partial_iteration.iterate!
  end

  if buffer
    build_rendered_template(buffer.to_s, first_template)
  else
    RenderedCollection.empty(@lookup_context.formats.first)
  end
end

#collection_with_template(view, template, layout, collection, &block) (private)

[ GitHub ]

  
# File 'actionview/lib/action_view/renderer/collection_renderer.rb', line 236

def collection_with_template(view, template, layout, collection, &block)
  locals = @locals
  cache = {}

  partial_iteration = PartialIteration.new(collection.size)

  collection.each_with_info.map do |object, (path, as, counter, iteration)|
    index = partial_iteration.index

    locals[as]        = object
    locals[counter]   = index
    locals[iteration] = partial_iteration

    _template, implicit_locals = (cache[path] ||= [template || find_template(path, @locals.keys + [as, counter, iteration]), [counter, iteration]])

    content = _template.render(view, locals, implicit_locals: implicit_locals, &block)
    content = layout.render(view, locals) { content } if layout
    partial_iteration.iterate!
    build_rendered_template(content, _template)
  end
end

#render_collection(collection, view, path, template, layout, block) (private)

[ GitHub ]

  
# File 'actionview/lib/action_view/renderer/collection_renderer.rb', line 153

def render_collection(collection, view, path, template, layout, block)
  identifier = (template && template.identifier) || path
  ActiveSupport::Notifications.instrument(
    "render_collection.action_view",
    identifier: identifier,
    layout: layout && layout.virtual_path,
    count: collection.length
  ) do |payload|
    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

    # Caching, per-item layouts and subclasses (like Jbuilder's, which
    # collects each item's result) need each item's body on its own,
    # and only templates that write into the buffer they are given can
    # share one. Otherwise every item is rendered into one shared
    # buffer, which saves a buffer and a RenderedTemplate per item that
    # would only be joined back together.
    if instance_of?(CollectionRenderer) && layout.nil? && template && renders_into_buffer?(template) && !will_cache?(@options, view)
      return collection_into_buffer(view, template, collection, spacer, &block)
    end

    collection_body = if template
      cache_collection_render(payload, view, template, collection) do |filtered_collection|
        collection_with_template(view, template, layout, filtered_collection, &block)
      end
    else
      collection_with_template(view, nil, layout, collection, &block)
    end

    return RenderedCollection.empty(@lookup_context.formats.first) if collection_body.empty?

    build_rendered_collection(collection_body, spacer)
  end
end

#render_collection_derive_partial(collection, context, block)

[ GitHub ]

  
# File 'actionview/lib/action_view/renderer/collection_renderer.rb', line 130

def render_collection_derive_partial(collection, context, block)
  paths = collection.map { |o| partial_path(o, context) }

  if paths.uniq.length == 1
    # Homogeneous
    render_collection_with_partial(collection, paths.first, context, block)
  else
    if @options[:cached]
      raise NotImplementedError, "render caching requires a template. Please specify a partial when rendering"
    end

    paths.map! { |path| retrieve_variable(path).unshift(path) }
    collection = MixedCollectionIterator.new(collection, paths)
    render_collection(collection, context, nil, nil, nil, block)
  end
end

#render_collection_with_partial(collection, partial, context, block)

[ GitHub ]

  
# File 'actionview/lib/action_view/renderer/collection_renderer.rb', line 112

def render_collection_with_partial(collection, partial, context, block)
  iter_vars  = retrieve_variable(partial)

  collection = if collection.respond_to?(:preload_associations)
    PreloadCollectionIterator.new(collection, partial, iter_vars, collection)
  else
    SameCollectionIterator.new(collection, partial, iter_vars)
  end

  template = find_template(partial, @locals.keys + iter_vars)

  layout = if !block && (layout = @options[:layout])
    find_template(layout.to_s, @locals.keys + iter_vars)
  end

  render_collection(collection, context, partial, template, layout, block)
end

#renders_into_buffer?(template) ⇒ Boolean (private)

ERB's compiled templates append to the output buffer they are run with. Other handlers (html, raw, Jbuilder, jb...) return their result instead, which Template#render drops when it is given a buffer, so their items have to be rendered one by one.

[ GitHub ]

  
# File 'actionview/lib/action_view/renderer/collection_renderer.rb', line 196

def renders_into_buffer?(template)
  Template::Handlers::ERB === template.handler
end

#retrieve_variable(path) (private)

[ GitHub ]

  
# File 'actionview/lib/action_view/renderer/collection_renderer.rb', line 148

def retrieve_variable(path)
  variable = local_variable(path)
  [variable, :"#{variable}_counter", :"#{variable}_iteration"]
end