Passing Parameters to yield in Rails 3 (or is it possible?)
Asked Answered
W

3

8

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ş

Williamson answered 25/5, 2012 at 9:17 Comment(3)
why do they need the same name? Sure ruby does magic but it does read minds.Onfre
with different names i have to duplicate my code. but i think i solve this problem with helpers. thanks for response anyway.Barrios
don't forget not duplicating code and single responsibility are both importantOnfre
K
9

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.

Kela answered 3/6, 2014 at 0:15 Comment(0)
G
2

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.

Gudren answered 25/5, 2012 at 11:26 Comment(0)
Z
2

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.

Zarger answered 10/9, 2012 at 16:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.