Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Pass block args for render :layout

#847

Currently it's possible to pass a block to "render :layout" in the view and yield to it. For example:


<!-- _layout.html.erb -->
before
<%= yield %>
end

<!-- some view --->
<%= render :layout => 'layout' do %>
middle
<% end %>

<!-- outputs -->
before
middle
end

However, you can not pass any arguments to that block when you yield. The included patch adds this ability. You can then do some really cool stuff like use that as an iterator if you pass a collection to layout.


<!-- _comment.html.erb -->
before
<%= yield comment %>
after

<!-- some view -->
<% render :layout => @comments do |comment| %>
  <%= comment.created_at %>
<% end %>

<!-- output -->
before
2008-01-01 00:00:00 (whatever time the comment was created)
after

This is very useful if you need to dynamically change some part of a partial when you're rendering it.

Reported by Ryan Bates · August 16th, 2008 @ 06:58 PM

State: resolved
Milestone: none
Assigned to: josh josh
Importance: none

Activity

  1. Ryan Bates
    Ryan Bates

    Also, you could get fancy and yield multiple times for different sections of the layout. For example.

    
    <!-- _comment.html.erb -->
    before
    <%= yield comment, :time %>
    middle
    <%= yield comment, :extra %>
    after
    
    <!-- some view -->
    <% render :layout => @comments do |comment, section| %>
      <% case section when :time %>
        <%= comment.created_at %>
      <% when :extra %>
        some extra content
      <% end %>
    <% end %>
    
    <!-- output -->
    before
    2008-01-01 00:00:00 (whatever time the comment was created)
    middle
    some extra content
    after
    

    This way you can easily and dynamically customize various parts of the layout/partial when rendering it.

    August 16th, 2008 @ 07:14 PM

  2. DHH
    DHH

    I like this, but we need to get some documentation on the method along with the patch.

    August 16th, 2008 @ 08:43 PM

  3. Ryan Bates
    Ryan Bates

    thanks, documentation is planned, just wanted to nail down the functionality first.

    August 16th, 2008 @ 08:46 PM

  4. Ryan Bates
    Ryan Bates

    Here's an updated patch with docs.

    August 16th, 2008 @ 09:15 PM

  5. josh
    josh

    If @proc_for_layout is private, lets prefix it with an underscore. I started doing that with a few other instance variables that are available in the view scope.

    The execute method was always a bad smell on Base. I wonder if we could easily move that over into the Renderable#render method. (This isn't exactly related to your patch buts its always nice to cleanup these little things when we spot them)

    August 17th, 2008 @ 05:05 AM

  6. Ryan Bates
    Ryan Bates

    Here's an updated patch with the underscore prefix. I'm not sure what's involved in moving the execute method over to renderable, so I'll leave that to you. :)

    August 17th, 2008 @ 05:29 AM

  7. Repository
    Repository
    • State changed from new to resolved

    (from [38c7d73e73d569211c4dfadf96fc295a925b7c9c]) pass yielded arguments to block for ActionView::Base#render with :layout [#847 Pass block args for render :layout state:resolved]

    Signed-off-by: Joshua Peek josh@joshpeek.com http://github.com/rails/rails/co...

    August 18th, 2008 @ 01:30 AM

  8. josh
    josh
    • Assigned user set to josh
    • Milestone cleared.
    • State changed from resolved to open

    Someone found a 2.1 regression bug due to this commit.

    The block arguments passed in shadow any existing @content_for_*.

    
    # index.erb
    <% content_for :column do %>column<% end %>
    <% render :layout => 'layouts/column' do %>content<% end %>
    
    # layouts/column.erb
    <div id="column"><%= yield :column %></div>
    <div id="content"><%= yield %></div>
    

    The "yield :column" always returns what is in the block "content" first and it never looks up @content_for_column.

    http://gist.github.com/20441

    October 28th, 2008 @ 05:34 PM

  9. Ryan Bates
    Ryan Bates

    This should be fixable by checking for the existence of the @content_for_* instance variable before executing the block. I'll try to write up a patch later today.

    October 28th, 2008 @ 06:56 PM

  10. josh
    josh

    I was playing with that idea but it got real hairy real fast. Good Luck :)

    October 28th, 2008 @ 08:36 PM

  11. Ryan Bates
    Ryan Bates

    Here's a patch which fixes this problem by checking for the existence of the content_for ivar before executing the block. Your tests are included.

    October 28th, 2008 @ 08:37 PM

  12. josh
    josh
    • State changed from open to resolved

    O, you make it look so easy :)

    October 29th, 2008 @ 02:23 AM

  13. Brendon
    Brendon

    I'm experiencing a bug when trying to yield a Date object. It results in:

    @content_for_2009-03-29' is not allowed as an instance variable name

    April 14th, 2009 @ 06:19 AM

  14. Ryan Bigg
    Ryan Bigg
    • Tag cleared.

    Automatic cleanup of spam.

    October 9th, 2010 @ 10:03 PM

  15. Ryan Bigg
    Ryan Bigg

    Automatic cleanup of spam.

    October 21st, 2010 @ 03:38 AM

  16. bingbing