Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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ş

like image 494
Çağdaş Avatar asked May 25 '12 09:05

Çağdaş


People also ask

What is yield in Rails?

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 ...

How should you use Content_for and yield?

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.


3 Answers

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.

like image 152
FuzzyJulz Avatar answered Oct 13 '22 04:10

FuzzyJulz


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.

like image 31
forker Avatar answered Oct 13 '22 04:10

forker


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.

like image 44
Isaac Betesh Avatar answered Oct 13 '22 03:10

Isaac Betesh