1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
|
# frozen_string_literal: true
require "action_view/renderer/collection_renderer" if Rails.version.to_f >= 6.1
module ViewComponent
class Collection
include Enumerable
attr_reader :component
delegate :format, to: :component
delegate :size, to: :@collection
attr_accessor :__vc_original_view_context
def set_original_view_context(view_context)
self.__vc_original_view_context = view_context
end
def render_in(view_context, &block)
components.map do |component|
component.set_original_view_context(__vc_original_view_context)
component.render_in(view_context, &block)
end.join.html_safe
end
def components
return @components if defined? @components
iterator = ActionView::PartialIteration.new(@collection.size)
component.validate_collection_parameter!(validate_default: true)
@components = @collection.map do |item|
component.new(**component_options(item, iterator)).tap do |component|
iterator.iterate!
end
end
end
def each(&block)
components.each(&block)
end
private
def initialize(component, object, **options)
@component = component
@collection = collection_variable(object || [])
@options = options
end
def collection_variable(object)
if object.respond_to?(:to_ary)
object.to_ary
else
raise ArgumentError.new(
"The value of the first argument passed to `with_collection` isn't a valid collection. " \
"Make sure it responds to `to_ary`."
)
end
end
def component_options(item, iterator)
item_options = {component.collection_parameter => item}
item_options[component.collection_counter_parameter] = iterator.index + 1 if component.counter_argument_present?
item_options[component.collection_iteration_parameter] = iterator.dup if component.iteration_argument_present?
@options.merge(item_options)
end
end
end
|