Added PartialIteration object used when rendering collections #7698

Closed
wants to merge 3 commits into
from

Projects

None yet

8 participants

@joeljunstrom
Contributor

Based on the ideas in #5634 but refactored into an object as per the comments.

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?+

For now the "template_name_counter" variable is kept but is deprecated.

@frodsan
Contributor
frodsan commented Oct 26, 2012
@frodsan frodsan commented on an outdated diff Oct 26, 2012
actionpack/test/controller/render_test.rb
@@ -630,6 +630,14 @@ def partial_collection_with_as
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') ]
@frodsan
frodsan Oct 26, 2012 Contributor

Please, change this to the 1.9 hash syntax. Thanks.

@frodsan frodsan commented on an outdated diff Oct 26, 2012
actionpack/test/controller/render_test.rb
@@ -630,6 +630,14 @@ def partial_collection_with_as
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
@frodsan
frodsan Oct 26, 2012 Contributor

ditto.

@frodsan frodsan and 1 other commented on an outdated diff Oct 26, 2012
actionpack/lib/action_view/partial_iteration.rb
@@ -0,0 +1,19 @@
+module ActionView
+ class PartialIteration
@frodsan
frodsan Oct 26, 2012 Contributor

Can you add documentation about this?

If you think this is not part of the public API, you can add a # :nodoc: directive.

Thanks.

@joeljunstrom
joeljunstrom Oct 26, 2012 Contributor

Yea I was unsure wether this should be documented or not. The methods are mentioned in the docs for render partial and I had a hard time finding examples of an similar utility value object. I'll go with nodoc for now.

@joeljunstrom
Contributor

Comments applied and rebased

@frodsan
Contributor
frodsan commented Oct 26, 2012

Please squash your commits.

@lucasuyezu
Contributor

+1 for this pull request. Since PartialIteration implements #index, I believe the best solution regarding variable_counter would be to print/log a deprecation warning and remove it in 4.1 or another release. I could try to implement this if you guys want. Also let me know if I can help with anything.

@SKoschnicke

+1. This would be a big improvement.

@joeljunstrom
Contributor

@lucasuyezu In the current implementation the counter is just a local variable making it a bit awkward adding a deprecation warning when accessing it.

If you have ideas on a implementation I can give you access to my repo.

@lucasuyezu
Contributor

@joeljunstrom We can turn the counter into a method with the same name that prints/logs the deprecation warning and return the variable. I will clone your repo and implement it.

@joeljunstrom
Contributor

Yea I just could'nt come up with what to put the method on =) Sounds good!

@lucasuyezu
Contributor

@joeljunstrom Done! Can I has repo acces?

@joeljunstrom
Contributor

@lucasuyezu sorry, I was sleeping =) You now have access!

@rafaelfranca
Member

@joeljunstrom @lucasuyezu guys, just ping me when done.

Thanks.

@joeljunstrom
Contributor

Will do

@lucasuyezu
Contributor

@rafaelfranca Would you like to take a look now? I believe it is ok.

@lucasuyezu
Contributor

@joeljunstrom @rafaelfranca hello? Is anyone there? 😟

@joeljunstrom
Contributor

@rafaelfranca & @lucasuyezu Sorry about the delay, I've rebased and squashed including lucasuyezu's additions (deprecating the use of the template_name_counter local. I'm a bit hesitant regarding the extra complexity surrounding the deprecation warning but maybe it does not matter much.

@carlosantoniodasilva carlosantoniodasilva and 3 others commented on an outdated diff Dec 19, 2012
actionpack/lib/action_view/template.rb
@@ -326,7 +327,27 @@ def handle_render_error(view, e) #:nodoc:
end
def locals_code #:nodoc:
- @locals.map { |key| "#{key} = local_assigns[:#{key}];" }.join
+ @locals.map do |key|
+ if key =~ /(.*)_counter$/
+ "self.#{key}= local_assigns[:#{key}];"
+ else
+ "#{key}= local_assigns[:#{key}];"
+ end
+ end.join
+ end
+
+ def define_locals_code #:nodoc:
+ @locals.map do |key|
+ if key =~ /(.*)_counter$/
+ <<-local_method
+ redefine_method(:#{key}=) { |new_value| @#{key}= new_value }
@carlosantoniodasilva
carlosantoniodasilva Dec 19, 2012 Member

I don't think we should make a setter method with an instance var for this, it'd be better to define everything in the same locals_code loop somehow.

@carlosantoniodasilva
carlosantoniodasilva Dec 19, 2012 Member

Btw, you probably don't need to set the variable, you can delegate to #{key}_iteration.index, right?

@lucasuyezu
lucasuyezu Dec 19, 2012 Contributor

I could try to use method_missing in the view object. In this scenario I would check if the method called is template_counter, warn and then return the value, making the redefine_method getters and setters unnecessary. But I still would need to keep either template_counter or template_iteration as an instance variable, because method_missing won't have access to local variables.

Does this sound better?

@carlosantoniodasilva
carlosantoniodasilva Dec 19, 2012 Member

I think we should avoid method missing if possible, but I don't have an idea off the top of my head, I'll try to think about something.

@joeljunstrom
joeljunstrom Dec 19, 2012 Contributor

I'm toying around with removing the name_counter variable from the partial renderer / locals and just setting up a method delegating to the iterator index. But tbh at the moment the module eval context in the template class is doing my head in =) Also it feels really dirty adding code to the template class for something that is just used for partials with collections, but I do not see a different way to do it yet.

@carlosantoniodasilva carlosantoniodasilva commented on the diff Dec 19, 2012
actionpack/test/template/partial_iteration_test.rb
@@ -0,0 +1,31 @@
+require 'abstract_unit'
+require 'action_view/partial_iteration'
+class PartialIterationTest < ActiveSupport::TestCase
@carlosantoniodasilva
carlosantoniodasilva Dec 19, 2012 Member

Add space before this line, and remove space after class and before the last end (the class body).

@carlosantoniodasilva carlosantoniodasilva commented on the diff Dec 19, 2012
actionpack/lib/action_view/partial_iteration.rb
+ 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
+
@carlosantoniodasilva
carlosantoniodasilva Dec 19, 2012 Member

No need for empty line.

@carlosantoniodasilva

Nice @joeljunstrom, I'd like to get this in for Rails 4 👍

@josevalim josevalim and 1 other commented on an outdated diff Mar 7, 2013
actionpack/lib/action_view/template.rb
@@ -281,6 +281,7 @@ def #{method_name}(local_assigns, output_buffer)
ensure
@virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
end
+ #{define_locals_code}
@josevalim
josevalim Mar 7, 2013 Member

I don't follow the need for this. Could someone please enlighten me?

@lucasuyezu
lucasuyezu Mar 7, 2013 Contributor

We want to show a deprecation warning when a user calls variable_counter instead of the new variable_iteration.index.
Since counter variables are local variables, this code defines a getter method for counter variables so we can warn and then return its original value.

@mattgoldman

any updates on this? is it pretty much good to go?

@joeljunstrom
Contributor

The problem is that getting this functionality with an deprecation warning for the old counter variable is as I see it pretty much impossible without adding (some what hard to follow) code to ActionView::Template without a major refactor of how locals are assigned to templates.

When looking at this again I have a hard time feeling the addition is worth hacking ActionView::Template.

So unless someone have a great idea of how to achieve this maybe we should close this for now 😕

@lucasuyezu
Contributor

The code is pretty much good to go, apart from the deprecation warning. I can revert it so this can ship, and prepare the deprecation warning on another pull request, if everybody agrees.

joeljunstrom and others added some commits Sep 16, 2012
@joeljunstrom @lucasuyezu joeljunstrom 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.
742989c
@lucasuyezu lucasuyezu Reverting deprecation warning. 290ddd1
@lucasuyezu lucasuyezu Fix broken spec from rebase. e3f9053
@lucasuyezu
Contributor

@joeljunstrom I have removed the deprecation warning. I also rebased the code based on the current rails master and fixed a spec that broke since then. Please let me know if there is any other thing blocking this.

@joeljunstrom
Contributor

I guess we should squash it and apply carlosantoniodasilva's formatting comments if I forgot to do it =)

@SKoschnicke

What prevents this from being merged? Can I help?

@rafaelfranca rafaelfranca added a commit to rafaelfranca/omg-rails that referenced this pull request Jul 16, 2014
@rafaelfranca rafaelfranca Add CHANGELOG entry for PartialIteration.
Closes #7698.
f5694a2
@rafaelfranca rafaelfranca added a commit that referenced this pull request Jul 16, 2014
@rafaelfranca rafaelfranca Merge branch 'joeljunstrom-local-iterator-for-partial-collections'
Squash and merge #7698 doing some improvements to the original
implementation.
1515569
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment