Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using multiple yields to insert content

I am trying to insert content on my page with yield but every time action removes whole content from the page. I have one main yield which is working fine:

<body>
    <%= render 'layouts/header' %>
    <div class="container">
      <%= yield %>
      <%= render 'layouts/footer' %>
    </div>
</body>

But inside that new content which is displayed on one page I have another yield:

<div class="container">
    <%= render 'admins/menu' %>
    <%= yield :admin %>
</div>

When user clicks on the menu which is rendered, new content should be displayed below that menu.

admins/_menu.html.erb

<div class="navbar">  
    <div class="navbar-inner">  
        <div class="container">  
            <ul class="nav">
                <li><%= link_to "Users", :controller => "admins", :action => "test" %></li>
                <li><%= link_to "1", ... %></li>
                <li><%= link_to "2", ... %></li>
                <li><%= link_to "3", ... %></li>
            </ul>
        </div>  
    </div>  
</div>  

Controller:

class AdminsController < ApplicationController

    def index
    end

    def test
        @users = User.paginate(page: params[:page])
    end
end

test.html.erb

<% content_for :admin do %>

<h1>All users</h1>

...

<% end %>

When I click on the option 'Users' from menu, page refreshes, menu disappears and nothing is displayed inside `body'. I want the content to be displayed below menu. How to use that second yield and accomplish this functionality?

I hope the question is not confusing. If question is confusing, please write me in comments and I will edit it immediately.

Thank you :)

like image 713
Cristiano Avatar asked Nov 18 '13 21:11

Cristiano


Video Answer


2 Answers

So, when you go to the index page you will get the piece of html that will be placed in the main layout, and this piece of html look like this:

<div class="container">
    <%= render 'admins/menu' %>
    <%= yield :admin %>
</div>

This code will yield :admin properly.

When you go to the test page you do not have this html code anymore (since it only belongs to the index method). So, anything you put in the content_for(:admin) block will be ignored since no-one is printing it.

What you probably want to do is creating a shared layout for all your admin pages. Follow this guide and you'll have your solution.

Solution

Edit the application.html.erb layout using this:

<%= content_for?(:content) ? yield(:content) : yield %>

instead of

<%= yield %>

Then create an admins.html.erb file inside the layouts folder to handle your admin pages' layout. Something like this:

<% content_for :content do %>
  <div class="container">
    <%= render 'admins/menu' %>
    <%= yield %>
  </div>
<% end %>
<%= render template: "layouts/application" %>

Will do fine. Then in the index.html.erb and test.html.erb just place regular HTML content, without using the content_for(:admin) block. Everything should work fine and you'll have your custom admin template, with a slightly different look from regular pages.

like image 148
marzapower Avatar answered Sep 22 '22 20:09

marzapower


Calling yield doesn't work in helper modules, while content_for does, so you should replace your yield calls in the helper files.

Also noteworthy: using provide is recommended over content_for when you're only using the method in 1 place instead of multiple places. You'll get better performance since it won't leave the buffer open while looking for more content, and your intent will be clearer to other developers that may see your code. (see http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#method-i-provide)

like image 23
Tyler Avatar answered Sep 25 '22 20:09

Tyler