mirror of https://github.com/rails/rails
Added PartialIteration class used when rendering collections
The iteration object is available as the local variable "template_name_iteration" when rendering partials with collections. It gives access to the +size+ of the collection beeing iterated over, the current +index+ and two convinicence methods +first?+ and +last?+ "template_name_counter" variable is kept but is deprecated. [Joel Junström + Lucas Uyezu]
This commit is contained in:
parent
6947e3a2b5
commit
1f5b360466
|
@ -0,0 +1,19 @@
|
|||
module ActionView
|
||||
class PartialIteration # :nodoc:
|
||||
attr_reader :size, :index
|
||||
|
||||
def initialize(size, index)
|
||||
@size = size
|
||||
@index = index
|
||||
end
|
||||
|
||||
def first?
|
||||
index == 0
|
||||
end
|
||||
|
||||
def last?
|
||||
index == size - 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -1,4 +1,5 @@
|
|||
require 'thread_safe'
|
||||
require "action_view/partial_iteration"
|
||||
|
||||
module ActionView
|
||||
# = Action View Partials
|
||||
|
@ -56,8 +57,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 +357,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,7 +390,7 @@ 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)
|
||||
|
@ -393,8 +398,11 @@ module ActionView
|
|||
|
||||
index = -1
|
||||
@collection.map do |object|
|
||||
locals[as] = object
|
||||
locals[counter] = (index += 1)
|
||||
index += 1
|
||||
|
||||
locals[as] = object
|
||||
locals[counter] = index
|
||||
locals[iteration] = PartialIteration.new(@collection.size, index)
|
||||
|
||||
content = template.render(view, locals)
|
||||
content = layout.render(view, locals) { content } if layout
|
||||
|
@ -410,10 +418,11 @@ module ActionView
|
|||
index = -1
|
||||
@collection.map do |object|
|
||||
index += 1
|
||||
path, as, counter = collection_data[index]
|
||||
path, as, counter, iteration = collection_data[index]
|
||||
|
||||
locals[as] = object
|
||||
locals[counter] = index
|
||||
locals[as] = object
|
||||
locals[counter] = index
|
||||
locals[iteration] = PartialIteration.new(@collection.size, index)
|
||||
|
||||
template = (cache[path] ||= find_template(path, keys + [as, counter]))
|
||||
template.render(view, locals)
|
||||
|
@ -466,8 +475,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 +489,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; " +
|
||||
|
|
|
@ -536,6 +536,14 @@ class TestController < ApplicationController
|
|||
render :partial => "customer_with_var", :collection => [ Customer.new("david"), Customer.new("mary") ], :as => :customer
|
||||
end
|
||||
|
||||
def partial_collection_with_iteration
|
||||
render partial: "customer_iteration", collection: [ Customer.new("david"), Customer.new("mary"), Customer.new('christine') ]
|
||||
end
|
||||
|
||||
def partial_collection_with_as_and_iteration
|
||||
render partial: "customer_iteration_with_as", collection: [ Customer.new("david"), Customer.new("mary"), Customer.new('christine') ], as: :client
|
||||
end
|
||||
|
||||
def partial_collection_with_counter
|
||||
render :partial => "customer_counter", :collection => [ Customer.new("david"), Customer.new("mary") ]
|
||||
end
|
||||
|
@ -1237,6 +1245,16 @@ class RenderTest < ActionController::TestCase
|
|||
assert_equal "david david davidmary mary mary", @response.body
|
||||
end
|
||||
|
||||
def test_partial_collection_with_iteration
|
||||
get :partial_collection_with_iteration
|
||||
assert_equal "3-0: david-first3-1: mary3-2: christine-last", @response.body
|
||||
end
|
||||
|
||||
def test_partial_collection_with_as_and_iteration
|
||||
get :partial_collection_with_as_and_iteration
|
||||
assert_equal "3-0: david-first3-1: mary3-2: christine-last", @response.body
|
||||
end
|
||||
|
||||
def test_partial_collection_with_counter
|
||||
get :partial_collection_with_counter
|
||||
assert_equal "david0mary1", @response.body
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<%= customer_iteration_iteration.size %>-<%= customer_iteration_iteration.index %>: <%= customer_iteration.name %><%= '-first' if customer_iteration_iteration.first? %><%= '-last' if customer_iteration_iteration.last? %>
|
|
@ -0,0 +1 @@
|
|||
<%= client_iteration.size %>-<%= client_iteration.index %>: <%= client.name %><%= '-first' if client_iteration.first? %><%= '-last' if client_iteration.last? %>
|
|
@ -0,0 +1,31 @@
|
|||
require 'abstract_unit'
|
||||
require 'action_view/partial_iteration'
|
||||
class PartialIterationTest < ActiveSupport::TestCase
|
||||
|
||||
def test_has_size_and_index
|
||||
iteration = ActionView::PartialIteration.new 3, 0
|
||||
assert_equal 0, iteration.index, "should be at the first index"
|
||||
assert_equal 3, iteration.size, "should have the size"
|
||||
end
|
||||
|
||||
def test_first_is_true_when_current_is_at_the_first_index
|
||||
iteration = ActionView::PartialIteration.new 3, 0
|
||||
assert iteration.first?, "first when current is 0"
|
||||
end
|
||||
|
||||
def test_first_is_false_unless_current_is_at_the_first_index
|
||||
iteration = ActionView::PartialIteration.new 3, 1
|
||||
assert !iteration.first?, "not first when current is 1"
|
||||
end
|
||||
|
||||
def test_last_is_true_when_current_is_at_the_last_index
|
||||
iteration = ActionView::PartialIteration.new 3, 2
|
||||
assert iteration.last?, "last when current is 2"
|
||||
end
|
||||
|
||||
def test_last_is_false_unless_current_is_at_the_last_index
|
||||
iteration = ActionView::PartialIteration.new 3, 0
|
||||
assert !iteration.last?, "not last when current is 0"
|
||||
end
|
||||
|
||||
end
|
|
@ -256,7 +256,7 @@ module RenderTestCases
|
|||
end
|
||||
|
||||
def test_render_partial_collection_without_as
|
||||
assert_equal "local_inspector,local_inspector_counter",
|
||||
assert_equal "local_inspector,local_inspector_counter,local_inspector_iteration",
|
||||
@view.render(:partial => "test/local_inspector", :collection => [ Customer.new("mary") ])
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue