Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Allow passing of array and block to layout #12875

Open
wants to merge 1 commit into from

2 participants

@macmartine

Fix for #12826 -- Layouts were unable to take arrays, as the docs state they should.

  • This problem starts with the block not getting passed to template.render in collection_with_template.

  • From there, we need to get the layout path (from the first object in the array).

  • Finally, in collection_with_template, we only want to call layout.render after template.render if a @options[:layout] does not equal @options[:partial]. The reason for this, is that when given an array, we use the first object in it to decide which layout is used.
    rendering_helper then sets the partial to the layout with: options.merge(:partial => options[:layout])
    We don't actually want to use the partial in this case though; If we were to call layout.render after template.render in this case we'd get un-desirable results when yielding the block.

Let me know if there's a preferable approach to this.

@robin850 robin850 added the actionview label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Nov 13, 2013
  1. @macmartine
This page is out of date. Refresh to see the latest.
View
22 actionview/lib/action_view/renderer/partial_renderer.rb
@@ -383,20 +383,32 @@ def find_template(path, locals)
@lookup_context.find_template(path, prefixes, true, locals, @details)
end
+ def layout_path
+ return nil if @options[:layout].blank?
+ if String === @options[:layout]
+ path = @options[:layout]
+ else
+ path = partial_path(@options[:layout].first)
+ end
+ end
+
+ def layout_matches_partial?
+ @options[:layout] == @options[:partial]
+ end
+
def collection_with_template
- view, locals, template = @view, @locals, @template
+ view, locals, template, block = @view, @locals, @template, @block
as, counter = @variable, @variable_counter
- if layout = @options[:layout]
- layout = find_template(layout, @template_keys)
- end
+ layout = layout_path unless layout_matches_partial?
+ layout = find_template(layout, @template_keys) if layout
index = -1
@collection.map do |object|
locals[as] = object
locals[counter] = (index += 1)
- content = template.render(view, locals)
+ content = template.render(view, locals, nil, &block)
content = layout.render(view, locals) { content } if layout
content
end
View
2  actionview/test/fixtures/users/_user.html.erb
@@ -0,0 +1,2 @@
+<%= greeting %>: <%= user.name %>
+<%= yield user %>
View
4 actionview/test/lib/controller/fake_models.rb
@@ -28,6 +28,10 @@ def persisted?
end
end
+class User < Struct.new(:name, :title)
+ include ActiveModel::Conversion
+end
+
class GoodCustomer < Customer
end
View
6 actionview/test/template/render_test.rb
@@ -340,6 +340,12 @@ def test_render_layout_with_block_and_other_partial_inside
assert_equal "Before\npartial html\nYield!\nAfter\n", render
end
+ def test_render_layout_with_array_and_block
+ users = [User.new("Mac", "developer"), User.new("Ryman", "pitcher")]
+ render = @controller_view.render(:layout => users, :locals => { :greeting => "Hello" }) { |user| "#{user.title}" }
+ assert_equal "Hello: Mac\ndeveloperHello: Ryman\npitcher", render
+ end
+
def test_render_inline
assert_equal "Hello, World!", @view.render(:inline => "Hello, World!")
end
Something went wrong with that request. Please try again.