public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
pass yielded arguments to block for ActionView::Base#render with :layout [#847 
state:resolved]

Signed-off-by: Joshua Peek <josh@joshpeek.com>
ryanb (author)
Sun Aug 17 17:29:24 -0700 2008
josh (committer)
Sun Aug 17 17:29:24 -0700 2008
commit  38c7d73e73d569211c4dfadf96fc295a925b7c9c
tree    9400fbbd277dafdde822fb9d3968f30764dbe9da
parent  dbb0abfb7e9eb9a63b721a38625e3eff66ced49d
...
246
247
248
249
 
 
250
 
 
251
252
253
 
 
254
 
 
255
256
257
...
367
368
369
370
371
372
373
374
375
376
377
378
379
...
392
393
394
395
396
397
398
399
400
401
402
...
246
247
248
 
249
250
251
252
253
254
255
 
256
257
258
259
260
261
262
263
...
373
374
375
 
 
 
 
 
 
 
376
377
378
...
391
392
393
 
 
 
 
 
 
394
395
0
@@ -246,12 +246,18 @@ module ActionView #:nodoc:
0
 
0
         if partial_layout = options.delete(:layout)
0
           if block_given?
0
-            wrap_content_for_layout capture(&block) do
0
+            begin
0
+              @_proc_for_layout = block
0
               concat(render(options.merge(:partial => partial_layout)))
0
+            ensure
0
+              @_proc_for_layout = nil
0
             end
0
           else
0
-            wrap_content_for_layout render(options) do
0
+            begin
0
+              original_content_for_layout, @content_for_layout = @content_for_layout, render(options)
0
               render(options.merge(:partial => partial_layout))
0
+            ensure
0
+              @content_for_layout = original_content_for_layout
0
             end
0
           end
0
         elsif options[:file]
0
@@ -367,13 +373,6 @@ module ActionView #:nodoc:
0
         InlineTemplate.new(text, type).render(self, local_assigns)
0
       end
0
 
0
-      def wrap_content_for_layout(content)
0
-        original_content_for_layout, @content_for_layout = @content_for_layout, content
0
-        yield
0
-      ensure
0
-        @content_for_layout = original_content_for_layout
0
-      end
0
-
0
       # Evaluate the local assigns and pushes them to the view.
0
       def evaluate_assigns
0
         unless @assigns_added
0
@@ -392,11 +391,5 @@ module ActionView #:nodoc:
0
           controller.response.content_type ||= content_type
0
         end
0
       end
0
-
0
-      def execute(method, local_assigns = {})
0
-        send(method, local_assigns) do |*names|
0
-          instance_variable_get "@content_for_#{names.first || 'layout'}"
0
-        end
0
-      end
0
   end
0
 end
...
68
69
70
71
 
72
73
74
...
82
83
84
85
 
86
87
88
...
101
102
103
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
105
106
...
68
69
70
 
71
72
73
74
...
82
83
84
 
85
86
87
88
...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
0
@@ -68,7 +68,7 @@ module ActionView
0
   #
0
   #   <%# app/views/users/_editor.html.erb &>
0
   #   <div id="editor">
0
-  #     Deadline: $<%= user.deadline %>
0
+  #     Deadline: <%= user.deadline %>
0
   #     <%= yield %>
0
   #   </div>
0
   #
0
@@ -82,7 +82,7 @@ module ActionView
0
   #
0
   #   Here's the editor:
0
   #   <div id="editor">
0
-  #     Deadline: $<%= user.deadline %>
0
+  #     Deadline: <%= user.deadline %>
0
   #     Name: <%= user.name %>
0
   #   </div>
0
   #
0
@@ -101,6 +101,40 @@ module ActionView
0
   #   </div>
0
   #
0
   # As you can see, the <tt>:locals</tt> hash is shared between both the partial and its layout.
0
+  #
0
+  # If you pass arguments to "yield" then this will be passed to the block. One way to use this is to pass
0
+  # an array to layout and treat it as an enumerable.
0
+  #
0
+  #   <%# app/views/users/_user.html.erb &>
0
+  #   <div class="user">
0
+  #     Budget: $<%= user.budget %>
0
+  #     <%= yield user %>
0
+  #   </div>
0
+  #
0
+  #   <%# app/views/users/index.html.erb &>
0
+  #   <% render :layout => @users do |user| %>
0
+  #     Title: <%= user.title %>
0
+  #   <% end %>
0
+  #
0
+  # This will render the layout for each user and yield to the block, passing the user, each time.
0
+  #
0
+  # You can also yield multiple times in one layout and use block arguments to differentiate the sections.
0
+  #
0
+  #   <%# app/views/users/_user.html.erb &>
0
+  #   <div class="user">
0
+  #     <%= yield user, :header %>
0
+  #     Budget: $<%= user.budget %>
0
+  #     <%= yield user, :footer %>
0
+  #   </div>
0
+  #
0
+  #   <%# app/views/users/index.html.erb &>
0
+  #   <% render :layout => @users do |user, section| %>
0
+  #     <%- case section when :header -%>
0
+  #       Title: <%= user.title %>
0
+  #     <%- when :footer -%>
0
+  #       Deadline: <%= user.deadline %>
0
+  #     <%- end -%>
0
+  #   <% end %>
0
   module Partials
0
     extend ActiveSupport::Memoizable
0
 
...
31
32
33
34
 
 
 
 
 
 
 
 
35
36
37
...
31
32
33
 
34
35
36
37
38
39
40
41
42
43
44
0
@@ -31,7 +31,14 @@ module ActionView
0
 
0
       view.send(:evaluate_assigns)
0
       view.send(:set_controller_content_type, mime_type) if respond_to?(:mime_type)
0
-      view.send(:execute, method_name(local_assigns), local_assigns)
0
+
0
+      view.send(method_name(local_assigns), local_assigns) do |*names|
0
+        if proc = view.instance_variable_get("@_proc_for_layout")
0
+          view.capture(*names, &proc)
0
+        else
0
+          view.instance_variable_get("@content_for_#{names.first || 'layout'}")
0
+        end
0
+      end
0
     end
0
 
0
     def method_name(local_assigns)
...
41
42
43
44
 
45
46
47
48
49
50
 
51
52
53
54
55
56
 
57
58
59
...
63
64
65
66
 
67
68
69
70
71
72
73
 
74
75
76
...
115
116
117
118
 
119
120
121
...
156
157
158
159
 
160
161
162
163
164
165
 
166
167
168
169
170
171
 
172
173
174
...
249
250
251
252
253
...
41
42
43
 
44
45
46
47
48
49
 
50
51
52
53
54
55
 
56
57
58
59
...
63
64
65
 
66
67
68
69
70
71
72
 
73
74
75
76
...
115
116
117
 
118
119
120
121
...
156
157
158
 
159
160
161
162
163
164
 
165
166
167
168
169
170
 
171
172
173
174
...
249
250
251
 
252
0
@@ -41,19 +41,19 @@ class LayoutAutoDiscoveryTest < Test::Unit::TestCase
0
 
0
     @request.host = "www.nextangle.com"
0
   end
0
-  
0
+
0
   def test_application_layout_is_default_when_no_controller_match
0
     @controller = ProductController.new
0
     get :hello
0
     assert_equal 'layout_test.rhtml hello.rhtml', @response.body
0
   end
0
-  
0
+
0
   def test_controller_name_layout_name_match
0
     @controller = ItemController.new
0
     get :hello
0
     assert_equal 'item.rhtml hello.rhtml', @response.body
0
   end
0
-  
0
+
0
   def test_third_party_template_library_auto_discovers_layout
0
     ThirdPartyTemplateLibraryController.view_paths.reload!
0
     @controller = ThirdPartyTemplateLibraryController.new
0
@@ -63,14 +63,14 @@ class LayoutAutoDiscoveryTest < Test::Unit::TestCase
0
     assert_response :success
0
     assert_equal 'Mab', @response.body
0
   end
0
-  
0
+
0
   def test_namespaced_controllers_auto_detect_layouts
0
     @controller = ControllerNameSpace::NestedController.new
0
     get :hello
0
     assert_equal 'layouts/controller_name_space/nested', @controller.active_layout
0
     assert_equal 'controller_name_space/nested.rhtml hello.rhtml', @response.body
0
   end
0
-  
0
+
0
   def test_namespaced_controllers_auto_detect_layouts
0
     @controller = MultipleExtensions.new
0
     get :hello
0
@@ -115,7 +115,7 @@ class ExemptFromLayoutTest < Test::Unit::TestCase
0
 
0
   def test_rhtml_exempt_from_layout_status_should_prevent_layout_render
0
     ActionController::Base.exempt_from_layout :rhtml
0
-    
0
+
0
     assert @controller.send!(:template_exempt_from_layout?, 'test.rhtml')
0
     assert @controller.send!(:template_exempt_from_layout?, 'hello.rhtml')
0
 
0
@@ -156,19 +156,19 @@ class LayoutSetInResponseTest < Test::Unit::TestCase
0
     get :hello
0
     assert_equal 'layouts/layout_test', @response.layout
0
   end
0
-  
0
+
0
   def test_layout_set_when_set_in_controller
0
     @controller = HasOwnLayoutController.new
0
     get :hello
0
     assert_equal 'layouts/item', @response.layout
0
   end
0
-  
0
+
0
   def test_layout_set_when_using_render
0
     @controller = SetsLayoutInRenderController.new
0
     get :hello
0
     assert_equal 'layouts/third_party_template_library', @response.layout
0
   end
0
-  
0
+
0
   def test_layout_is_not_set_when_none_rendered
0
     @controller = RendersNoLayoutController.new
0
     get :hello
0
@@ -249,4 +249,3 @@ class LayoutSymlinkedIsRenderedTest < Test::Unit::TestCase
0
     assert_equal "layouts/symlinked/symlinked_layout", @response.layout
0
   end
0
 end
0
-    
0
\ No newline at end of file
...
435
436
437
 
 
 
 
438
439
440
...
969
970
971
 
 
 
 
 
972
...
435
436
437
438
439
440
441
442
443
444
...
973
974
975
976
977
978
979
980
981
0
@@ -435,6 +435,10 @@ class NewRenderTestController < ActionController::Base
0
     render :action => "using_layout_around_block"
0
   end
0
 
0
+  def render_using_layout_around_block_with_args
0
+    render :action => "using_layout_around_block_with_args"
0
+  end
0
+
0
   def render_using_layout_around_block_in_main_layout_and_within_content_for_layout
0
     render :action => "using_layout_around_block"
0
   end
0
@@ -969,4 +973,9 @@ EOS
0
     get :render_using_layout_around_block_in_main_layout_and_within_content_for_layout
0
     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
0
   end
0
+
0
+  def test_using_layout_around_block_with_args
0
+    get :render_using_layout_around_block_with_args
0
+    assert_equal "Before\narg1arg2\nAfter", @response.body
0
+  end
0
 end

Comments

supaspoida Mon Aug 18 00:39:51 -0700 2008

This looks awesome, excited to play with it. Thanks Ryan!