From e72374d0ff8b149bdbf8e14a703cbc2028df520c Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 26 Apr 2012 20:24:53 -0300 Subject: Allow layout rendering to access current object being rendered when using partial + collection --- actionpack/lib/action_view/renderer/partial_renderer.rb | 17 +++++++++++------ .../test/_b_layout_for_partial_with_object.html.erb | 1 + actionpack/test/template/render_test.rb | 8 ++++++-- 3 files changed, 18 insertions(+), 8 deletions(-) create mode 100644 actionpack/test/fixtures/test/_b_layout_for_partial_with_object.html.erb diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 34ea06c9cf..449cf08fd0 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -283,13 +283,19 @@ module ActionView end if layout = @options[:layout] - layout = find_template(layout) + layout = find_template(layout, @locals.keys + [@variable]) end result = @template ? collection_with_template : collection_without_template - - result.map!{|content| layout.render(@view, @locals) { content } } if layout - + + if layout + locals = @locals + result.map! do |content| + locals[@variable] = @collection[result.index(content)] + layout.render(@view, @locals) { content } + end + end + result.join(spacer).html_safe end @@ -391,10 +397,9 @@ module ActionView locals[as] = object segments << template.render(@view, locals) end - + segments end - def collection_without_template segments, locals, collection_data = [], @locals, @collection_data diff --git a/actionpack/test/fixtures/test/_b_layout_for_partial_with_object.html.erb b/actionpack/test/fixtures/test/_b_layout_for_partial_with_object.html.erb new file mode 100644 index 0000000000..bdd53014cd --- /dev/null +++ b/actionpack/test/fixtures/test/_b_layout_for_partial_with_object.html.erb @@ -0,0 +1 @@ +<%= yield %> \ No newline at end of file diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 43b176df3c..5fe725ec31 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -233,11 +233,15 @@ module RenderTestCases def test_render_partial_with_nil_values_in_collection assert_equal "Hello: davidHello: Anonymous", @view.render(:partial => "test/customer", :collection => [ Customer.new("david"), nil ]) end - + def test_render_partial_with_layout_using_collection_and_template assert_equal "Hello: AmazonHello: Yahoo", @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end + def test_render_partial_with_layout_using_collection_and_template_makes_current_item_available_in_template + assert_equal 'Hello: AmazonHello: Yahoo', @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) + end + def test_render_partial_with_empty_array_should_return_nil assert_nil @view.render(:partial => []) end @@ -310,7 +314,7 @@ module RenderTestCases ActionView::Template.register_template_handler :foo, CustomHandler assert_equal 'source: "Hello, <%= name %>!"', @view.render(:inline => "Hello, <%= name %>!", :locals => { :name => "Josh" }, :type => :foo) end - + def test_render_knows_about_types_registered_when_extensions_are_checked_earlier_in_initialization ActionView::Template::Handlers.extensions ActionView::Template.register_template_handler :foo, CustomHandler -- cgit v1.2.3 From d0c9c93c4a3a7da27ab8d9f53811960309f8e18f Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 26 Apr 2012 20:36:35 -0300 Subject: Allow layout to access current object being rendered when using render partial + object --- actionpack/lib/action_view/renderer/partial_renderer.rb | 2 +- actionpack/test/template/render_test.rb | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 449cf08fd0..c7765732c7 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -304,7 +304,7 @@ module ActionView object, as = @object, @variable if !block && (layout = @options[:layout]) - layout = find_template(layout) + layout = find_template(layout, @locals.keys + [@variable]) end object ||= locals[as] diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 5fe725ec31..a76526f946 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -242,6 +242,10 @@ module RenderTestCases assert_equal 'Hello: AmazonHello: Yahoo', @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end + def test_render_partial_with_layout_using_object_and_template_makes_object_available_in_template + assert_equal 'Hello: Amazon', @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :object => Customer.new("Amazon")) + end + def test_render_partial_with_empty_array_should_return_nil assert_nil @view.render(:partial => []) end -- cgit v1.2.3 From 0568fb5b9efa6923e9407552aae46b0a1210539d Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 26 Apr 2012 20:47:22 -0300 Subject: Allow access to current object_counter variable from layout when rendering with partial + collection --- actionpack/lib/action_view/renderer/partial_renderer.rb | 3 ++- .../_b_layout_for_partial_with_object_counter.html.erb | 1 + actionpack/test/template/render_test.rb | 15 +++++++++++---- 3 files changed, 14 insertions(+), 5 deletions(-) create mode 100644 actionpack/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index c7765732c7..e2b5e8e36e 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -283,7 +283,7 @@ module ActionView end if layout = @options[:layout] - layout = find_template(layout, @locals.keys + [@variable]) + layout = find_template(layout, @locals.keys + [@variable, @variable_counter]) end result = @template ? collection_with_template : collection_without_template @@ -292,6 +292,7 @@ module ActionView locals = @locals result.map! do |content| locals[@variable] = @collection[result.index(content)] + locals[@variable_counter] = result.index(content) layout.render(@view, @locals) { content } end end diff --git a/actionpack/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb b/actionpack/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb new file mode 100644 index 0000000000..44d6121297 --- /dev/null +++ b/actionpack/test/fixtures/test/_b_layout_for_partial_with_object_counter.html.erb @@ -0,0 +1 @@ +<%= yield %> \ No newline at end of file diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index a76526f946..cdaca56ef2 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -238,12 +238,19 @@ module RenderTestCases assert_equal "Hello: AmazonHello: Yahoo", @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end - def test_render_partial_with_layout_using_collection_and_template_makes_current_item_available_in_template - assert_equal 'Hello: AmazonHello: Yahoo', @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) + def test_render_partial_with_layout_using_collection_and_template_makes_current_item_available_in_layout + assert_equal 'Hello: AmazonHello: Yahoo', + @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) end - def test_render_partial_with_layout_using_object_and_template_makes_object_available_in_template - assert_equal 'Hello: Amazon', @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :object => Customer.new("Amazon")) + def test_render_partial_with_layout_using_collection_and_template_makes_current_item_counter_available_in_layout + assert_equal 'Hello: AmazonHello: Yahoo', + @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object_counter', :collection => [ Customer.new("Amazon"), Customer.new("Yahoo") ]) + end + + def test_render_partial_with_layout_using_object_and_template_makes_object_available_in_layout + assert_equal 'Hello: Amazon', + @view.render(:partial => "test/customer", :layout => 'test/b_layout_for_partial_with_object', :object => Customer.new("Amazon")) end def test_render_partial_with_empty_array_should_return_nil -- cgit v1.2.3 From 228f9910389cad7fe0dd7f2bd010fe654f794b37 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 26 Apr 2012 21:24:58 -0300 Subject: Move layout logic with collection to be handled only with explicit template is given Layout is never an available option when rendering with the shortcut `render @collection`. --- .../lib/action_view/renderer/partial_renderer.rb | 23 ++++++++-------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index e2b5e8e36e..2b38834217 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -282,21 +282,7 @@ module ActionView spacer = find_template(@options[:spacer_template]).render(@view, @locals) end - if layout = @options[:layout] - layout = find_template(layout, @locals.keys + [@variable, @variable_counter]) - end - result = @template ? collection_with_template : collection_without_template - - if layout - locals = @locals - result.map! do |content| - locals[@variable] = @collection[result.index(content)] - locals[@variable_counter] = result.index(content) - layout.render(@view, @locals) { content } - end - end - result.join(spacer).html_safe end @@ -391,12 +377,19 @@ module ActionView segments, locals, template = [], @locals, @template as, counter = @variable, @variable_counter + if layout = @options[:layout] + layout = find_template(layout, @locals.keys + [@variable, @variable_counter]) + end + locals[counter] = -1 @collection.each do |object| locals[counter] += 1 locals[as] = object - segments << template.render(@view, locals) + + content = template.render(@view, locals) + content = layout.render(@view, locals) { content } if layout + segments << content end segments -- cgit v1.2.3 From ab318d2828683521f75cfa448a6560ef7edd2246 Mon Sep 17 00:00:00 2001 From: Carlos Antonio da Silva Date: Thu, 26 Apr 2012 22:06:41 -0300 Subject: Add changelog entry and some docs for collection + layout --- actionpack/CHANGELOG.md | 3 +++ actionpack/lib/action_view/renderer/partial_renderer.rb | 10 +++++++--- guides/source/layouts_and_rendering.textile | 10 ++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 6940bd45a0..dc152b7a6e 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,5 +1,8 @@ ## Rails 4.0.0 (unreleased) ## +* Make current object and counter (when it applies) variables accessible when + rendering templates with :object / :collection. *Carlos Antonio da Silva* + * JSONP now uses mimetype application/javascript instead of application/json *omjokine* * Allow to lazy load `default_form_builder` by passing a `String` instead of a constant. *Piotr Sarnacki* diff --git a/actionpack/lib/action_view/renderer/partial_renderer.rb b/actionpack/lib/action_view/renderer/partial_renderer.rb index 2b38834217..c5d5540510 100644 --- a/actionpack/lib/action_view/renderer/partial_renderer.rb +++ b/actionpack/lib/action_view/renderer/partial_renderer.rb @@ -158,8 +158,8 @@ module ActionView # Name: <%= user.name %> # # - # If a collection is given, the layout will be rendered once for each item in the collection. Just think - # these two snippets have the same output: + # If a collection is given, the layout will be rendered once for each item in + # the collection. Just think these two snippets have the same output: # # <%# app/views/users/_user.html.erb %> # Name: <%= user.name %> @@ -184,7 +184,7 @@ module ActionView # <%= render :partial => "user", :layout => "li_layout", :collection => users %> # # - # Given two users whose names are Alice and Bob, these snippets return: + # Given two users whose names are Alice and Bob, these snippets return: # #
    #
  • @@ -195,6 +195,10 @@ module ActionView #
  • #
# + # The current object being rendered, as well as the object_counter, will be + # available as local variables inside the layout template under the same names + # as available in the partial. + # # You can also apply a layout to a block within any template: # # <%# app/views/users/_chief.html.erb &> diff --git a/guides/source/layouts_and_rendering.textile b/guides/source/layouts_and_rendering.textile index c2bba56581..f69afaa281 100644 --- a/guides/source/layouts_and_rendering.textile +++ b/guides/source/layouts_and_rendering.textile @@ -1193,6 +1193,16 @@ h5. Spacer Templates Rails will render the +_product_ruler+ partial (with no data passed in to it) between each pair of +_product+ partials. +h5. Partial Layouts + +When rendering collections it is also possible to use the +:layout+ option: + + +<%= render :partial => "product", :collection => @products, :layout => "special_layout" %> + + +The layout will be rendered together with the partial for each item in the collection. The current object and object_counter variables will be available in the layout as well, the same way they do within the partial. + h4. Using Nested Layouts You may find that your application requires a layout that differs slightly from your regular application layout to support one particular controller. Rather than repeating the main layout and editing it, you can accomplish this by using nested layouts (sometimes called sub-templates). Here's an example: -- cgit v1.2.3