Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

content_for with flush parameter #4226

Merged
merged 1 commit into from

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Dec 29, 2011
  1. grentis
This page is out of date. Refresh to see the latest.
37 actionpack/lib/action_view/helpers/capture_helper.rb
View
@@ -81,8 +81,8 @@ def capture(*args)
# <%# This is the layout %>
# <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
# <head>
- # <title>My Website</title>
- # <%= yield :script %>
+ # <title>My Website</title>
+ # <%= yield :script %>
# </head>
# <body>
# <%= yield %>
@@ -110,7 +110,7 @@ def capture(*args)
# That will place +script+ tags for your default set of JavaScript files on the page;
# this technique is useful if you'll only be using these scripts in a few views.
#
- # Note that content_for concatenates the blocks it is given for a particular
+ # Note that content_for concatenates (default) the blocks it is given for a particular
# identifier in order. For example:
#
# <% content_for :navigation do %>
@@ -127,16 +127,37 @@ def capture(*args)
#
# <ul><%= content_for :navigation %></ul>
#
+ # If the flush parameter is true content_for replaces the blocks it is given. For example:
+ #
+ # <% content_for :navigation do %>
+ # <li><%= link_to 'Home', :action => 'index' %></li>
+ # <% end %>
+ #
+ # <%# Add some other content, or use a different template: %>
+ #
+ # <% content_for :navigation, true do %>
+ # <li><%= link_to 'Login', :action => 'login' %></li>
+ # <% end %>
+ #
+ # Then, in another template or layout, this code would render only the last link:
+ #
+ # <ul><%= content_for :navigation %></ul>
+ #
# Lastly, simple content can be passed as a parameter:
#
# <% content_for :script, javascript_include_tag(:defaults) %>
#
# WARNING: content_for is ignored in caches. So you shouldn't use it
# for elements that will be fragment cached.
- def content_for(name, content = nil, &block)
+ def content_for(name, content = nil, flush = false, &block)
if content || block_given?
- content = capture(&block) if block_given?
- @view_flow.append(name, content) if content
+ if block_given?
+ flush = content if content
+ content = capture(&block)
+ end
+ if content
+ flush ? @view_flow.set(name, content) : @view_flow.append(name, content)
+ end
nil
else
@view_flow.get(name)
@@ -164,8 +185,8 @@ def provide(name, content = nil, &block)
# <%# This is the layout %>
# <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
# <head>
- # <title>My Website</title>
- # <%= yield :script %>
+ # <title>My Website</title>
+ # <%= yield :script %>
# </head>
# <body class="<%= content_for?(:right_col) ? 'one-column' : 'two-column' %>">
# <%= yield %>
55 actionpack/test/template/capture_helper_test.rb
View
@@ -53,6 +53,13 @@ def test_content_for_with_multiple_calls
assert_equal 'foobar', content_for(:title)
end
+ def test_content_for_with_multiple_calls_and_flush
+ assert ! content_for?(:title)
+ content_for :title, 'foo'
+ content_for :title, 'bar', true
+ assert_equal 'bar', content_for(:title)
+ end
+
def test_content_for_with_block
assert ! content_for?(:title)
content_for :title do
@@ -63,6 +70,39 @@ def test_content_for_with_block
assert_equal 'foobar', content_for(:title)
end
+ def test_content_for_with_block_and_multiple_calls_with_flush
+ assert ! content_for?(:title)
+ content_for :title do
+ 'foo'
+ end
+ content_for :title, true do
+ 'bar'
+ end
+ assert_equal 'bar', content_for(:title)
+ end
+
+ def test_content_for_with_block_and_multiple_calls_with_flush_nil_content
+ assert ! content_for?(:title)
+ content_for :title do
+ 'foo'
+ end
+ content_for :title, nil, true do
+ 'bar'
+ end
+ assert_equal 'bar', content_for(:title)
+ end
+
+ def test_content_for_with_block_and_multiple_calls_without_flush
+ assert ! content_for?(:title)
+ content_for :title do
+ 'foo'
+ end
+ content_for :title, false do
+ 'bar'
+ end
+ assert_equal 'foobar', content_for(:title)
+ end
+
def test_content_for_with_whitespace_block
assert ! content_for?(:title)
content_for :title, 'foo'
@@ -74,12 +114,27 @@ def test_content_for_with_whitespace_block
assert_equal 'foobar', content_for(:title)
end
+ def test_content_for_with_whitespace_block_and_flush
+ assert ! content_for?(:title)
+ content_for :title, 'foo'
+ content_for :title, true do
+ output_buffer << " \n "
+ nil
+ end
+ content_for :title, 'bar', true
+ assert_equal 'bar', content_for(:title)
+ end
+
def test_content_for_returns_nil_when_writing
assert ! content_for?(:title)
assert_equal nil, content_for(:title, 'foo')
assert_equal nil, content_for(:title) { output_buffer << 'bar'; nil }
assert_equal nil, content_for(:title) { output_buffer << " \n "; nil }
assert_equal 'foobar', content_for(:title)
+ assert_equal nil, content_for(:title, 'foo', true)
+ assert_equal nil, content_for(:title, true) { output_buffer << 'bar'; nil }
+ assert_equal nil, content_for(:title, true) { output_buffer << " \n "; nil }
+ assert_equal 'bar', content_for(:title)
end
def test_content_for_question_mark
Something went wrong with that request. Please try again.