Reputation: 1023
I'm trying to create a dynamic content with yield
and content_for
. Basically i have bunch of layouts. And i dont want to create bunch of views for each layout. I want to render view parts when they are needed. For different parts of code it is ok. But i have problem with same parts with different content.
in my application.html.erb
<%= yield %>
<%= yield :name_section %>
And in my show.html.erb
i have;
<% content_for :name_section do %>
<b>Name:</b>
<%= @post.name %>
<% end %>
Here is the question;
What if i want to multiple name_section with different contents. I mean; I want to put :name_section
different places in my view with different contents.
For ex;
<table>
<tr>
<td>
<%= yield :name_section %>
</td>
</tr>
<tr>
<td>
<%= yield :name_section %>
</td>
</tr>
</table>
Any ideas?
Thank you. Çağdaş
Upvotes: 8
Views: 7403
Reputation: 2874
I believe that what you were asking for is now possible:
# The template
<%= render layout: "my_layout" do |customer| %>
Hello <%= customer.name %>
<% end %>
# The layout
<html>
<%= yield Struct.new(:name).new("David") %>
</html>
From: http://api.rubyonrails.org/classes/ActionView/Helpers/RenderingHelper.html#method-i-_layout_for
Hopefully this helps someone else looking for the same solution.
Upvotes: 9
Reputation: 3000
The following solution has worked nicely for me. It doesn't allow you to pass args, but if, right before calling content_for
(the second time), you assign your args to instance variables, this allows you to reference your instance variables in content_for
. The basic idea is that content_for
generates the content when it is called the 1st time and that content then remains static, but this workaround delays that static content generation until you're ready to display the content.
First, add this function to your helper module:
def immediate_content_for name, content = nil, &block
@immediate_content ||= {}
if content || block_given? then
@immediate_content[name] = Proc.new { content_for name, content, &block }
nil
else
@immediate_content[name].call
content_for name
end
end
Then, suppose you want to pass arg1
to content_for
. You can now do this:
<% content_for :my_form %>
<%= some_helper_function(@arg1) %>
<% end %>
Then, later in your code, after your defined arg1
:
<%= @arg1 = arg1 %>
<%= content_for :my_form %>
It's a hack in the sense that I can't guarantee that the behavior of immediate_content_for
is in all other way identical to that of content_for
, and if the behavior of content_for
changes in some future version of rails, you'll need to update immediate_content_for
if you want it to continue mirroring content_for
. Although it's not an optimal solution, it does the job for now.
Upvotes: 2
Reputation: 2679
Given the documentation:
http://api.rubyonrails.org/classes/ActionView/Helpers/RenderingHelper.html#method-i-_layout_for
and the source code of the method (you can browse it there):
def _layout_for(*args, &block)
name = args.first
if block && !name.is_a?(Symbol)
capture(*args, &block)
else
super
end
end
What you are asking for is not possible with yield
in layout.
Upvotes: 2