I was looking at how content_for works and observed the block.call
in the capture_erb_with_buffer
method. It apparently magically writes to the buf
This little tiny method called execute
in ActionView::Base
explains it all.
http://google.com/codesearch/p?hl=en#m8Vht-lU3vE/vendor/rails/actionpack/lib/action_view/base.rb&q=capture_helper.rb&d=5&l=337
def execute(template)
send(template.method, template.locals) do |*names|
instance_variable_get "@content_for_#{names.first || 'layout'}"
end
end
The do |*names|... end
block is the one receiving the yield
. You'll notice that the @content_for_#{names.first}
matches up with the variable being set in the content_for
process.
It's called from AV::TemplateHandlers::Compilable in #render, and I would assume other places as well.
def render(template)
@view.send :execute, template
end
http://google.com/codesearch/p?hl=en#m8Vht-lU3vE/vendor/rails/actionpack/lib/action_view/template_handlers/compilable.rb&q=execute&exact_package=git://github.com/payalgupta/todo-list.git&sa=N&cd=17&ct=rc&l=28
Simply:
calling yield in a method executes code that was passed to the method via a block.
For instance
def my_method
yield
end
my_method { puts "Hello" }
my_method { puts "World" }
these 5 lines will produce the following output to the screen
Hello
World
See the following page for a nice discussion of yield in Ruby: Ruby Yield
I'm not certain how yield
functions on the ERB level, but I do know how it works when applied to layouts.
Heres a sample layout.html.erb file:
<html>
<head>
<title> <%= @title || 'Plain Title' %> </title>
<%= yield :head %>
</head>
<body>
<div id='menu'>
<%= yield :menu %>
</div>
<div id='content'>
<%= yield %>
</div>
<div id='footer'>
<%= yield :footer %>
</div>
</body>
I have defined 4 yields(:head, :menu, :footer, and default) and an instance variable @title.
Now controller actions can render views that slot into these spots. Note that the view renders before the layout, so I can define a variable like @title in a view and have it defined in the layout.
Sample views: An About page
<% @title = 'About' %>
<% content_for :menu do %>
<%= link_to 'Back to Home', :action => :home %>
<% end %>
We rock!
<% content_for :footer do %>
An Illinois based company.
<% end %>
An Edit page
<% @title = 'Edit' %>
<% content_for :head do %>
<style type='text/css'> .edit_form div {display:inline-block;} </style>
<% end %>
<% form_for :thing, :html => {:class => 'edit_form'} do |f| %>
...
<% end %>
You can mix and match what yields you want to put data in, and what occurs in the content_for :something
will be inserted in the matching yield :something
in the layout file.
It even works for partials, a partial can insert its own content_for :something block which will get added with any other content_for calls.