aboutsummaryrefslogtreecommitdiffstats
path: root/actionview/lib
diff options
context:
space:
mode:
authorRafael Mendonça França <rafaelmfranca@gmail.com>2014-07-16 14:56:35 -0300
committerRafael Mendonça França <rafaelmfranca@gmail.com>2014-07-16 14:56:35 -0300
commit15155692b4cc9577def5c7ee80fd3d22c5c986b1 (patch)
treedd485677928ce0dcc16620ed2c5a0f5900f91596 /actionview/lib
parent6947e3a2b57b62e1d6bd24082faa125973bbc388 (diff)
parent03d77504be20fbd170a25e948f259ad4047d0d3e (diff)
downloadrails-15155692b4cc9577def5c7ee80fd3d22c5c986b1.tar.gz
rails-15155692b4cc9577def5c7ee80fd3d22c5c986b1.tar.bz2
rails-15155692b4cc9577def5c7ee80fd3d22c5c986b1.zip
Merge branch 'joeljunstrom-local-iterator-for-partial-collections'
Squash and merge #7698 doing some improvements to the original implementation.
Diffstat (limited to 'actionview/lib')
-rw-r--r--actionview/lib/action_view/renderer/partial_renderer.rb78
1 files changed, 61 insertions, 17 deletions
diff --git a/actionview/lib/action_view/renderer/partial_renderer.rb b/actionview/lib/action_view/renderer/partial_renderer.rb
index 36f17f01fd..eb8db16796 100644
--- a/actionview/lib/action_view/renderer/partial_renderer.rb
+++ b/actionview/lib/action_view/renderer/partial_renderer.rb
@@ -1,6 +1,33 @@
require 'thread_safe'
module ActionView
+ class PartialIteration
+ # The number of iterations that will be done by the partial.
+ attr_reader :size
+
+ # The current iteration of the partial.
+ attr_reader :index
+
+ def initialize(size)
+ @size = size
+ @index = 0
+ end
+
+ # Check if this is the first iteration of the partial.
+ def first?
+ index == 0
+ end
+
+ # Check if this is the last iteration of the partial.
+ def last?
+ index == size - 1
+ end
+
+ def iterate! # :nodoc:
+ @index += 1
+ end
+ end
+
# = Action View Partials
#
# There's also a convenience method for rendering sub templates within the current controller that depends on a
@@ -56,8 +83,12 @@ module ActionView
# <%= render partial: "ad", collection: @advertisements %>
#
# This will render "advertiser/_ad.html.erb" and pass the local variable +ad+ to the template for display. An
- # iteration counter will automatically be made available to the template with a name of the form
- # +partial_name_counter+. In the case of the example above, the template would be fed +ad_counter+.
+ # iteration object will automatically be made available to the template with a name of the form
+ # +partial_name_iteration+. The iteration object has knowledge about which index the current object has in
+ # the collection and the total size of the collection. The iteration object also has two convenience methods,
+ # +first?+ and +last?+. In the case of the example above, the template would be fed +ad_iteration+.
+ # For backwards compatibility the +partial_name_counter+ is still present and is mapped to the iteration's
+ # +index+ method.
#
# The <tt>:as</tt> option may be used when rendering partials.
#
@@ -352,7 +383,7 @@ module ActionView
end
if @path
- @variable, @variable_counter = retrieve_variable(@path, as)
+ @variable, @variable_counter, @variable_iteration = retrieve_variable(@path, as)
@template_keys = retrieve_template_keys
else
paths.map! { |path| retrieve_variable(path, as).unshift(path) }
@@ -385,19 +416,22 @@ module ActionView
def collection_with_template
view, locals, template = @view, @locals, @template
- as, counter = @variable, @variable_counter
+ as, counter, iteration = @variable, @variable_counter, @variable_iteration
if layout = @options[:layout]
layout = find_template(layout, @template_keys)
end
- index = -1
+ partial_interation = PartialIteration.new(@collection.size)
+ locals[iteration] = partial_interation
+
@collection.map do |object|
- locals[as] = object
- locals[counter] = (index += 1)
+ locals[as] = object
+ locals[counter] = partial_interation.index
content = template.render(view, locals)
content = layout.render(view, locals) { content } if layout
+ partial_interation.iterate!
content
end
end
@@ -407,16 +441,20 @@ module ActionView
cache = {}
keys = @locals.keys
- index = -1
+ partial_interation = PartialIteration.new(@collection.size)
+
@collection.map do |object|
- index += 1
- path, as, counter = collection_data[index]
+ index = partial_interation.index
+ path, as, counter, iteration = collection_data[index]
- locals[as] = object
- locals[counter] = index
+ locals[as] = object
+ locals[counter] = index
+ locals[iteration] = partial_interation
template = (cache[path] ||= find_template(path, keys + [as, counter]))
- template.render(view, locals)
+ content = template.render(view, locals)
+ partial_interation.iterate!
+ content
end
end
@@ -466,8 +504,11 @@ module ActionView
def retrieve_template_keys
keys = @locals.keys
- keys << @variable if @object || @collection
- keys << @variable_counter if @collection
+ keys << @variable if @object || @collection
+ if @collection
+ keys << @variable_counter
+ keys << @variable_iteration
+ end
keys
end
@@ -477,8 +518,11 @@ module ActionView
raise_invalid_identifier(path) unless base =~ /\A_?([a-z]\w*)(\.\w+)*\z/
$1.to_sym
end
- variable_counter = :"#{variable}_counter" if @collection
- [variable, variable_counter]
+ if @collection
+ variable_counter = :"#{variable}_counter"
+ variable_iteration = :"#{variable}_iteration"
+ end
+ [variable, variable_counter, variable_iteration]
end
IDENTIFIER_ERROR_MESSAGE = "The partial name (%s) is not a valid Ruby identifier; " +