Using multiple yields to insert content
Asked Answered
G

3

5

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 :)

Godewyn answered 18/11, 2013 at 21:35 Comment(4)
In which file is the <%= yield :admin %> code placed?Pentstemon
Just a hunch, but instead of <%= yield :admin %>, have you tried <%= content_for :admin %>?Thinner
@Pentstemon - In views/admins/index.html.erbGodewyn
@Thinner - I tried but it's the same.Godewyn
P
16

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.

Pentstemon answered 18/11, 2013 at 22:10 Comment(7)
Thank you but how can I now access that admins.html.erb file? I have a link <li><%= link_to "Admin dashboard", admin_dashboard_path %></li> on main page and in routes there was: match '/admin_dashboard', to: 'admins#index', via: 'get'.Godewyn
The admins.html.erb file (placed in the layouts folder near the application main layout) will be automatically loaded for each method of the AdminsController. See that as an extension of the application.html.erb layout.Pentstemon
It works and it loads automatically but the problem is that admins.html.erb completely erases everything and now I have completely blank page only with the menu on top without any styles.Godewyn
Have you modified the application layout as requested? You should just substitute the <%= yield %> line, not the whole file!Pentstemon
Yes. I substituted <%= yield %> with <%= content_for?(:content) ? yield(:content) : yield %>. Now when I click on 'Admin dashboard' on menu, only 'clean' admins.html.erb file opens without any styles.Godewyn
Sorry, I messed up the answer while typing, and pasted the wrong code. I updated the admin template. Let me know!Pentstemon
Thank you, it works now! I just recently started learning Rails so it was all a little bit confusing for me. You saved the day :)Godewyn
H
1

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)

Hymeneal answered 18/11, 2013 at 22:18 Comment(0)
S
0

I found that you have to add an yield (without actually outputing) before the namespaced tags.

<div>
  <% yield %>
  <div class="mt-3">
    <div class="text-2xl tracking-wide font-bold text-gray-900">
      heading
      <%= yield :heading %>
    </div>
  </div>

  <div class="relative bg-white rounded-xl shadow-xl mb-8 min-h-28">
    <%= yield %>
  </div>
...
Semmes answered 5/1, 2021 at 13:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.