Skip to content
This repository

content_for with flush parameter #4226

Merged
merged 1 commit into from over 2 years ago

3 participants

grentis José Valim Prem Sichanugrist
grentis

Hi all,
I have a problem using content_for with nested layouts. I have a template like this one

...
    <h1><%= content_for :box_title %></h1>
    <div class="box_content">
      <%= yield %>
    </div>
...

called for render multiple partials from a view

...
  <%= render partial: 'agents_box', layout: 'layouts/internal/box' %>
  <%= render partial: 'users_box', layout: 'layouts/internal/box' %>
...

_agents_box.html.erb

<% content_for_clear :box_title do %>Server Management<% end %>

_users_box.html.erb

<% content_for_clear :box_title do %>Users<% end %>

Due to the behavior of the content_for function (concatenate) the page is not displayed correctly. (the first h1 contains "Server Management" and the second one "Server ManagementUsers")

In order to solve this kind of problem I updated the content_for method to accept another parameter (flush - false by default) used to decide if the content should be concatenated or replaced.

Using this in my example the page is displayed in the right way

_agents_box.html.erb

<% content_for :box_title, true do %>Server Management<% end %>

_users_box.html.erb

<% content_for :box_title, true do %>Users<% end %>

Hope this can be useful also for other people

José Valim
Owner

It looks good, but we probably should do something like this: flush = content if block_given? so we don't always need to pass the second parameter as nil when using the block form.

Prem Sichanugrist
Collaborator

Agree with @josevalim. Would you please fix that and force-push to your branch?

grentis

I made the changes... I hope I have done the right things with the force-push process

José Valim josevalim merged commit 5ac0273 into from December 29, 2011
José Valim josevalim closed this December 29, 2011
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Dec 29, 2011
grentis content_for with flush parameter 8a130ed
This page is out of date. Refresh to see the latest.
37  actionpack/lib/action_view/helpers/capture_helper.rb
@@ -81,8 +81,8 @@ def capture(*args)
81 81
       #   <%# This is the layout %>
82 82
       #   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
83 83
       #   <head>
84  
-      #	    <title>My Website</title>
85  
-      #	    <%= yield :script %>
  84
+      #     <title>My Website</title>
  85
+      #     <%= yield :script %>
86 86
       #   </head>
87 87
       #   <body>
88 88
       #     <%= yield %>
@@ -110,7 +110,7 @@ def capture(*args)
110 110
       # That will place +script+ tags for your default set of JavaScript files on the page;
111 111
       # this technique is useful if you'll only be using these scripts in a few views.
112 112
       #
113  
-      # Note that content_for concatenates the blocks it is given for a particular
  113
+      # Note that content_for concatenates (default) the blocks it is given for a particular
114 114
       # identifier in order. For example:
115 115
       #
116 116
       #   <% content_for :navigation do %>
@@ -127,16 +127,37 @@ def capture(*args)
127 127
       #
128 128
       #   <ul><%= content_for :navigation %></ul>
129 129
       #
  130
+      # If the flush parameter is true content_for replaces the blocks it is given. For example:
  131
+      #
  132
+      #   <% content_for :navigation do %>
  133
+      #     <li><%= link_to 'Home', :action => 'index' %></li>
  134
+      #   <% end %>
  135
+      #
  136
+      #   <%#  Add some other content, or use a different template: %>
  137
+      #
  138
+      #   <% content_for :navigation, true do %>
  139
+      #     <li><%= link_to 'Login', :action => 'login' %></li>
  140
+      #   <% end %>
  141
+      #
  142
+      # Then, in another template or layout, this code would render only the last link:
  143
+      #
  144
+      #   <ul><%= content_for :navigation %></ul>
  145
+      #
130 146
       # Lastly, simple content can be passed as a parameter:
131 147
       #
132 148
       #   <% content_for :script, javascript_include_tag(:defaults) %>
133 149
       #
134 150
       # WARNING: content_for is ignored in caches. So you shouldn't use it
135 151
       # for elements that will be fragment cached.
136  
-      def content_for(name, content = nil, &block)
  152
+      def content_for(name, content = nil, flush = false, &block)
137 153
         if content || block_given?
138  
-          content = capture(&block) if block_given?
139  
-          @view_flow.append(name, content) if content
  154
+          if block_given?
  155
+            flush = content if content
  156
+            content = capture(&block)
  157
+          end
  158
+          if content
  159
+            flush ? @view_flow.set(name, content) : @view_flow.append(name, content)
  160
+          end
140 161
           nil
141 162
         else
142 163
           @view_flow.get(name)
@@ -164,8 +185,8 @@ def provide(name, content = nil, &block)
164 185
       #   <%# This is the layout %>
165 186
       #   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
166 187
       #   <head>
167  
-      #	    <title>My Website</title>
168  
-      #	    <%= yield :script %>
  188
+      #     <title>My Website</title>
  189
+      #     <%= yield :script %>
169 190
       #   </head>
170 191
       #   <body class="<%= content_for?(:right_col) ? 'one-column' : 'two-column' %>">
171 192
       #     <%= yield %>
55  actionpack/test/template/capture_helper_test.rb
@@ -53,6 +53,13 @@ def test_content_for_with_multiple_calls
53 53
     assert_equal 'foobar', content_for(:title)
54 54
   end
55 55
 
  56
+  def test_content_for_with_multiple_calls_and_flush
  57
+    assert ! content_for?(:title)
  58
+    content_for :title, 'foo'
  59
+    content_for :title, 'bar', true
  60
+    assert_equal 'bar', content_for(:title)
  61
+  end
  62
+
56 63
   def test_content_for_with_block
57 64
     assert ! content_for?(:title)
58 65
     content_for :title do
@@ -63,6 +70,39 @@ def test_content_for_with_block
63 70
     assert_equal 'foobar', content_for(:title)
64 71
   end
65 72
 
  73
+  def test_content_for_with_block_and_multiple_calls_with_flush
  74
+    assert ! content_for?(:title)
  75
+    content_for :title do
  76
+      'foo'
  77
+    end
  78
+    content_for :title, true do
  79
+      'bar'
  80
+    end
  81
+    assert_equal 'bar', content_for(:title)
  82
+  end
  83
+
  84
+  def test_content_for_with_block_and_multiple_calls_with_flush_nil_content
  85
+    assert ! content_for?(:title)
  86
+    content_for :title do
  87
+      'foo'
  88
+    end
  89
+    content_for :title, nil, true do
  90
+      'bar'
  91
+    end
  92
+    assert_equal 'bar', content_for(:title)
  93
+  end
  94
+
  95
+  def test_content_for_with_block_and_multiple_calls_without_flush
  96
+    assert ! content_for?(:title)
  97
+    content_for :title do
  98
+      'foo'
  99
+    end
  100
+    content_for :title, false do
  101
+      'bar'
  102
+    end
  103
+    assert_equal 'foobar', content_for(:title)
  104
+  end
  105
+
66 106
   def test_content_for_with_whitespace_block
67 107
     assert ! content_for?(:title)
68 108
     content_for :title, 'foo'
@@ -74,12 +114,27 @@ def test_content_for_with_whitespace_block
74 114
     assert_equal 'foobar', content_for(:title)
75 115
   end
76 116
 
  117
+  def test_content_for_with_whitespace_block_and_flush
  118
+    assert ! content_for?(:title)
  119
+    content_for :title, 'foo'
  120
+    content_for :title, true do
  121
+      output_buffer << "  \n  "
  122
+      nil
  123
+    end
  124
+    content_for :title, 'bar', true
  125
+    assert_equal 'bar', content_for(:title)
  126
+  end
  127
+
77 128
   def test_content_for_returns_nil_when_writing
78 129
     assert ! content_for?(:title)
79 130
     assert_equal nil, content_for(:title, 'foo')
80 131
     assert_equal nil, content_for(:title) { output_buffer << 'bar'; nil }
81 132
     assert_equal nil, content_for(:title) { output_buffer << "  \n  "; nil }
82 133
     assert_equal 'foobar', content_for(:title)
  134
+    assert_equal nil, content_for(:title, 'foo', true)
  135
+    assert_equal nil, content_for(:title, true) { output_buffer << 'bar'; nil }
  136
+    assert_equal nil, content_for(:title, true) { output_buffer << "  \n  "; nil }
  137
+    assert_equal 'bar', content_for(:title)
83 138
   end
84 139
 
85 140
   def test_content_for_question_mark
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.