5

I'm looking for solution to have partial with multiple yields.

In real example I have this views structure:

Basic application.erb (/views/layouts/application.erb):

<!DOCTYPE html>
<head>
    <title>Some title</title>
</head>
<body>
<div class="page">
    <%= yield %>
</div>
</body>
</html> 

Some partial to DRY my code (/views/shared/content.erb):

<div class="content">
    <div class="sidebar">
        <%= yield :sidebar %>
    </div>
    <div class="main">
        <%= yield %>
    </div>
</div>

And controller view (/views/home/index.erb):

<%= render :partial => 'layouts/header' %>    
<%= render :partial => 'shared/navigation' %>

<% # It is close to what I want to do %>
<%= render :layout => 'shared/content' do %>
    <% content_for :sidebar do %>
        <%# This is will go to application.erb, not in content.erb %>
        <%= render :partial => 'shared/menu' %>
    <% end %>

    <%= yield %>
<% end %>

<%= render :partial => 'layouts/footer' %>

So the main issue here is to have a template block with multiple yield areas and ability to pass custom html or render another partial.

3 Answers 3

15

This question is old, however, it's still relevant when I was searching for an answer on Google.

I've come up with a solution, while still not beautiful, works very well. The idea uses Rails' capture method, which takes a block and stores its contents into a variable:

controller.html.erb

<%= render 'shared/partial', body: capture { %>
  My body content
<% }, footer: capture { %>
  My footer content
<% } %>

shared/_partial.html.erb

<div id="body"><%= body %></div>
<div id="footer"><%= footer %></div>

Hope this helps someone!

Sign up to request clarification or add additional context in comments.

Comments

5

In my case I've found solution like this.

On my controller view (/views/home/index.erb):

<% sidebar_content = render :partial => 'shared/slider' %>
<%= render :layout => 'shared/content', :locals => {:sidebar => sidebar_content} do %>
    <%= yield %>
<% end %>

The partial with multiple areas (/views/shared/content.erb):

<div class="content">
    <div class="sidebar">
        <%= sidebar %>
    </div>
    <div class="main">
        <%= yield %>
    </div>
</div>

This solution doesn't look pretty, but it works. I hope to find something better in near future.

1 Comment

Nope. I've changed my workflow with templates. I use only partials, and trying to avoid passig another partial as a parameter. Particularly in mentioned example, i'll create a 'content' partial with 'menu' inside. /shared/content/default.erb, /shared/content/with_menu.erb
1

Here is my solution:

/views/shared/_content.erb

<div class="content">
    <div class="sidebar">
        <%= yield :sidebar %>
    </div>
    <div class="main">
        <%= yield %>
    </div>
</div>

views/home/index.erb


<%= my_content_tag do %>
    <% content_for :sidebar do %>
        <%= render :partial => 'shared/menu' %>
    <% end %>

    <%= yield %>
<% end %>

app/helpers/my_tags_helper.rb

module MyTagsHelper
  def my_content_tag(&block)
    sidebar_backup = @view_flow.content.delete(:sidebar)
    x = capture(&block)
    html = render('shared/content') { x }
    @view_flow.content[:sidebar] = sidebar_backup if sidebar_backup
    html
  end
end

The key is using capture to extract content_for block and pass it into @view_flow

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.