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ş
yield is a keyword in Ruby which allow the developer to pass some argument to block from the yield, the number of the argument passed to the block has no limitations, the main advantage of using yield in Ruby, if we face any situation we wanted to our method perform different functions according to calling block, which ...
Basically, it says, "if content_for?(:title) is present in the view file, use yield(:title) to include it, otherwise just display 'brand.name' which is 'PyGoogle'. The main body of the view will always render into the unnamed yield. To render content into a named yield, we use the content_for method.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With