Çağdaş
Çağdaş

Reputation: 1023

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

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

Answers (3)

FuzzyJulz
FuzzyJulz

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

Isaac Betesh
Isaac Betesh

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

forker
forker

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

Related Questions