From 38c7d73e73d569211c4dfadf96fc295a925b7c9c Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Sun, 17 Aug 2008 19:29:24 -0500 Subject: pass yielded arguments to block for ActionView::Base#render with :layout [#847 state:resolved] Signed-off-by: Joshua Peek --- actionpack/lib/action_view/base.rb | 23 +++++-------- actionpack/lib/action_view/partials.rb | 38 ++++++++++++++++++++-- actionpack/lib/action_view/renderable.rb | 9 ++++- actionpack/test/controller/layout_test.rb | 19 +++++------ actionpack/test/controller/new_render_test.rb | 9 +++++ .../test/_layout_for_block_with_args.html.erb | 3 ++ .../using_layout_around_block_with_args.html.erb | 1 + 7 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb create mode 100644 actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb (limited to 'actionpack') diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index ad59d92086..f7f9f70298 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -246,12 +246,18 @@ module ActionView #:nodoc: if partial_layout = options.delete(:layout) if block_given? - wrap_content_for_layout capture(&block) do + begin + @_proc_for_layout = block concat(render(options.merge(:partial => partial_layout))) + ensure + @_proc_for_layout = nil end else - wrap_content_for_layout render(options) do + begin + original_content_for_layout, @content_for_layout = @content_for_layout, render(options) render(options.merge(:partial => partial_layout)) + ensure + @content_for_layout = original_content_for_layout end end elsif options[:file] @@ -367,13 +373,6 @@ module ActionView #:nodoc: InlineTemplate.new(text, type).render(self, local_assigns) end - def wrap_content_for_layout(content) - original_content_for_layout, @content_for_layout = @content_for_layout, content - yield - ensure - @content_for_layout = original_content_for_layout - end - # Evaluate the local assigns and pushes them to the view. def evaluate_assigns unless @assigns_added @@ -392,11 +391,5 @@ module ActionView #:nodoc: controller.response.content_type ||= content_type end end - - def execute(method, local_assigns = {}) - send(method, local_assigns) do |*names| - instance_variable_get "@content_for_#{names.first || 'layout'}" - end - end end end diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/partials.rb index 894b88534c..b661a62677 100644 --- a/actionpack/lib/action_view/partials.rb +++ b/actionpack/lib/action_view/partials.rb @@ -68,7 +68,7 @@ module ActionView # # <%# app/views/users/_editor.html.erb &> #
- # Deadline: $<%= user.deadline %> + # Deadline: <%= user.deadline %> # <%= yield %> #
# @@ -82,7 +82,7 @@ module ActionView # # Here's the editor: #
- # Deadline: $<%= user.deadline %> + # Deadline: <%= user.deadline %> # Name: <%= user.name %> #
# @@ -101,6 +101,40 @@ module ActionView # # # As you can see, the :locals hash is shared between both the partial and its layout. + # + # If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass + # an array to layout and treat it as an enumerable. + # + # <%# app/views/users/_user.html.erb &> + #
+ # Budget: $<%= user.budget %> + # <%= yield user %> + #
+ # + # <%# app/views/users/index.html.erb &> + # <% render :layout => @users do |user| %> + # Title: <%= user.title %> + # <% end %> + # + # This will render the layout for each user and yield to the block, passing the user, each time. + # + # You can also yield multiple times in one layout and use block arguments to differentiate the sections. + # + # <%# app/views/users/_user.html.erb &> + #
+ # <%= yield user, :header %> + # Budget: $<%= user.budget %> + # <%= yield user, :footer %> + #
+ # + # <%# app/views/users/index.html.erb &> + # <% render :layout => @users do |user, section| %> + # <%- case section when :header -%> + # Title: <%= user.title %> + # <%- when :footer -%> + # Deadline: <%= user.deadline %> + # <%- end -%> + # <% end %> module Partials extend ActiveSupport::Memoizable diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/renderable.rb index 89ac500717..a28689dc69 100644 --- a/actionpack/lib/action_view/renderable.rb +++ b/actionpack/lib/action_view/renderable.rb @@ -31,7 +31,14 @@ module ActionView view.send(:evaluate_assigns) view.send(:set_controller_content_type, mime_type) if respond_to?(:mime_type) - view.send(:execute, method_name(local_assigns), local_assigns) + + view.send(method_name(local_assigns), local_assigns) do |*names| + if proc = view.instance_variable_get("@_proc_for_layout") + view.capture(*names, &proc) + else + view.instance_variable_get("@content_for_#{names.first || 'layout'}") + end + end end def method_name(local_assigns) diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index 72c01a9102..71f110f241 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -41,19 +41,19 @@ class LayoutAutoDiscoveryTest < Test::Unit::TestCase @request.host = "www.nextangle.com" end - + def test_application_layout_is_default_when_no_controller_match @controller = ProductController.new get :hello assert_equal 'layout_test.rhtml hello.rhtml', @response.body end - + def test_controller_name_layout_name_match @controller = ItemController.new get :hello assert_equal 'item.rhtml hello.rhtml', @response.body end - + def test_third_party_template_library_auto_discovers_layout ThirdPartyTemplateLibraryController.view_paths.reload! @controller = ThirdPartyTemplateLibraryController.new @@ -63,14 +63,14 @@ class LayoutAutoDiscoveryTest < Test::Unit::TestCase assert_response :success assert_equal 'Mab', @response.body end - + def test_namespaced_controllers_auto_detect_layouts @controller = ControllerNameSpace::NestedController.new get :hello assert_equal 'layouts/controller_name_space/nested', @controller.active_layout assert_equal 'controller_name_space/nested.rhtml hello.rhtml', @response.body end - + def test_namespaced_controllers_auto_detect_layouts @controller = MultipleExtensions.new get :hello @@ -115,7 +115,7 @@ class ExemptFromLayoutTest < Test::Unit::TestCase def test_rhtml_exempt_from_layout_status_should_prevent_layout_render ActionController::Base.exempt_from_layout :rhtml - + assert @controller.send!(:template_exempt_from_layout?, 'test.rhtml') assert @controller.send!(:template_exempt_from_layout?, 'hello.rhtml') @@ -156,19 +156,19 @@ class LayoutSetInResponseTest < Test::Unit::TestCase get :hello assert_equal 'layouts/layout_test', @response.layout end - + def test_layout_set_when_set_in_controller @controller = HasOwnLayoutController.new get :hello assert_equal 'layouts/item', @response.layout end - + def test_layout_set_when_using_render @controller = SetsLayoutInRenderController.new get :hello assert_equal 'layouts/third_party_template_library', @response.layout end - + def test_layout_is_not_set_when_none_rendered @controller = RendersNoLayoutController.new get :hello @@ -249,4 +249,3 @@ class LayoutSymlinkedIsRenderedTest < Test::Unit::TestCase assert_equal "layouts/symlinked/symlinked_layout", @response.layout end end - \ No newline at end of file diff --git a/actionpack/test/controller/new_render_test.rb b/actionpack/test/controller/new_render_test.rb index be99350cd2..82919b7777 100644 --- a/actionpack/test/controller/new_render_test.rb +++ b/actionpack/test/controller/new_render_test.rb @@ -435,6 +435,10 @@ class NewRenderTestController < ActionController::Base render :action => "using_layout_around_block" end + def render_using_layout_around_block_with_args + render :action => "using_layout_around_block_with_args" + end + def render_using_layout_around_block_in_main_layout_and_within_content_for_layout render :action => "using_layout_around_block" end @@ -969,4 +973,9 @@ EOS get :render_using_layout_around_block_in_main_layout_and_within_content_for_layout assert_equal "Before (Anthony)\nInside from first block in layout\nAfter\nBefore (David)\nInside from block\nAfter\nBefore (Ramm)\nInside from second block in layout\nAfter\n", @response.body end + + def test_using_layout_around_block_with_args + get :render_using_layout_around_block_with_args + assert_equal "Before\narg1arg2\nAfter", @response.body + end end diff --git a/actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb b/actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb new file mode 100644 index 0000000000..307533208d --- /dev/null +++ b/actionpack/test/fixtures/test/_layout_for_block_with_args.html.erb @@ -0,0 +1,3 @@ +Before +<%= yield 'arg1', 'arg2' %> +After \ No newline at end of file diff --git a/actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb b/actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb new file mode 100644 index 0000000000..71b1f30ad0 --- /dev/null +++ b/actionpack/test/fixtures/test/using_layout_around_block_with_args.html.erb @@ -0,0 +1 @@ +<% render(:layout => "layout_for_block_with_args") do |*args| %><%= args.join %><% end %> \ No newline at end of file -- cgit v1.2.3