how to use content_for so that the content shows up in the layout
Asked Answered
G

2

8

Am testing the content_for in my rails 3.2 app and following the rails guides but they are specific to the actual files and I cannot seem to get the yield to work:

application.html.erb file:

 <!DOCTYPE html>
 <html>
<head>
 ...
</head>

<body>




<%= yield :navigation %> #shouldn't this load the content_for block named :navigation specified in the _main_nav.html.erb partial? 

 <%= yield %>  #this load the index page content


</body>
 </html>

I created a layout file _main_nav.html.erb (i know I can render with <%= render 'layouts/header' %> but I am trying to use the content_for instead) The _main_nav.html.erb is:

<% content_for :navigation do %>
<ul>
 <li>Home</li>
 </ul>

<% end %>

They way I read the RailsGuide http://guides.rubyonrails.org/layouts_and_rendering.html#using-the-content-for-method this should work. But it does not. I do not get an error. Seems simple but I am stumped.

When I go to my index.html.erb file I would expect to see this result:

  • Home
Glob answered 19/7, 2013 at 23:55 Comment(0)
B
10

OK, I think I have a solution for this. Your code:

<% content_for :navigation do %>
<ul>
<li>Home</li>
</ul>
<% end %>

should be at the top of the file that is loading. Your _header.html.erb is a partial. If you move this code into views/tasks/new.html.erb then it works as expected.

However, for it to work as you want, then you need to adjust your application.html.erb file:

<p>this is where we should see the "Home" link appear that is defined in _header.html.erb:</p>
<section class="header">
<% render 'layouts/header' %>
<%= yield :navigation %>
</section>

Notice, that I have called the render erb tag without the = sign. This means I don't see the contents of the header partial, but it does load. If you include the = sign then it still works but also renders any other content you may have in the partial. Note: The render tag has to be above/before the yield tag.

Blab answered 17/3, 2015 at 12:9 Comment(1)
no worries @akkdio, I also did a pull request to your GitHub repo. Any questions just ask. I'm a newbie, but I think I understand what is going on with this one!Blab
A
15

I believe what you want to have is have a view that will contain your content_for block. So an example would be if you have the following:

index.html.erb

<% content_for :head do %> 
  <%= stylesheet_link_tag 'users' %> 
  #Above this will load the users stylesheet
<% end %> 

<h2>Example</h2> 
  <ul>
    <% @users.each do |users| %> 
      <li><%= user.name %></li>
    <% end %> 
  </ul>

Then to output what inside the users stylesheet we can yield and pass in the symbol of the name of the content_for.

Application.html.erb

    <!-DOCTYPE html> 
      <html> 
        <head> 
         <%= yield :head%>
           <title>This is my title</title 
         </head> 
        <body>
        <p>This is a test</p> 
        <%= yield %> 
     </html> 

So to review whats happening here is that, in my example I am saying I have a users stylesheet that I would like to load into the <head></head> of my application.html.erb. To do this I set the content_for which is a Rails helper and give it the identifier sysmbol which is head which is then called in the application.html.erb where I do yeild :head. So what I am getting my application to do is when the my index.html.erb for that page is being rendered the application.html.erb will load my users stylesheet. Hope this clears things up for you.

Update explanation

To add to this another thing the purpose of combination of using content_for with yield is to allow you to inject data into the application layout from ANY view. So as another example. You could have the following:

<% content_for :title do %> My Title<% end %> 

Here when the controller renders the view template and combines it with the application layout, the text My title will be replaced. The yield(:head) makes it easy to add more elements to the specific page if needed. Take a look at the following example:

app/views/layouts/application.html.erb

<% if content_for?(:navbar) %>
  <%= yield(:navbar) %>
<% else %>
  <%# default navbar %>
  <section class="navbar"></section>
<% end %>

app/views/blah/index.html.erb

<% content_for(:navbar) do %>
  <section class="navbar"></section>
<% end %>

And a further note not sure how your developing your application or what design framework your using but you could also take a look at Rails-Bootstrap-Navbar. May also be an alternative.

Ashleeashleigh answered 20/7, 2013 at 10:36 Comment(7)
David, Thank you. You are correct in that my example was not like the guide -I have updated it to be more specific about what I am trying to do... It seems that the content_for block should be abled to be called anywhere in the views by just putting <%= yield :header %> however I cannot even get this simple example to work. I must not be understanding it or have to do something else to get things to appear...Glob
David, I really appreciate you taking the time to understand my question and am sorry it was a little confusing... I see what you have done and understand it as it relates to the stylesheet. Where I am unclear is why when I try to create a nav to use the content_for nothing shows up? Please if you can look at my reworked example and let me know if you spot anything wrong in my thinking.Glob
@Glob take another look at the further updated example with an additional linkAshleeashleigh
David, Thank you again. I tried your example in my app and it did not work. It is something simple I am sure. But what? To help I put my example on Github ( github.com/akkdio/content_for ) with the hope that a quick look will spot my error and thinking. The bootstrap link is interesting... however, I am attempting to understand bits and pieces first. Thank you again.Glob
@Glob can you actually explain to me why you are actually rendering two yield blocks in the body tag. I don't know if it just me but I think you separate this out in to some sort of div. So maybe for your header you could have <div class="container_header"></div> and encase your yeild` inside this. If this does not work you could just simply try and do <%= render 'layouts/header' and have done with and have this render your content for you.Ashleeashleigh
David, The example is contrived to focus on the content_for and try to get it to work. I pushed an update to git to make it more "realistic" adding section divs. The point was to learn about the content_for method to be able use it. I will continue to try to understand why my example is wrong. However, I thank you for your help and time you took to get me a little further down the path...Glob
Helped me to understand how this helper method really work.. Thanks!!Spendable
B
10

OK, I think I have a solution for this. Your code:

<% content_for :navigation do %>
<ul>
<li>Home</li>
</ul>
<% end %>

should be at the top of the file that is loading. Your _header.html.erb is a partial. If you move this code into views/tasks/new.html.erb then it works as expected.

However, for it to work as you want, then you need to adjust your application.html.erb file:

<p>this is where we should see the "Home" link appear that is defined in _header.html.erb:</p>
<section class="header">
<% render 'layouts/header' %>
<%= yield :navigation %>
</section>

Notice, that I have called the render erb tag without the = sign. This means I don't see the contents of the header partial, but it does load. If you include the = sign then it still works but also renders any other content you may have in the partial. Note: The render tag has to be above/before the yield tag.

Blab answered 17/3, 2015 at 12:9 Comment(1)
no worries @akkdio, I also did a pull request to your GitHub repo. Any questions just ask. I'm a newbie, but I think I understand what is going on with this one!Blab

© 2022 - 2024 — McMap. All rights reserved.