I'm new to rails and am trying to work out how to get nested layouts working; I'm assuming they're a bit like .net master pages?
I've followed this guide and I've created an application.erb.html in my layout directory which contains this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<title><%= #page_title or 'Page Title' %></title>
<%= stylesheet_link_tag 'layout' %>
<style type="text/css"><%= yield :stylesheets %></style>
</head>
<body>
<%= yield(:content) or yield %>
</body>
</html>
and have modified one of my existing layouts to this:
<% content_for :stylesheets do %>
<% end -%>
<% content_for :content do %>
<p style="color: green"><%= flash[:notice] %></p>
<%= yield %>
<% end -%>
<% render :file => 'layouts/application' %>
When I go to one of my views in the browser, absolutely nothing is rendered; when I view source there is no html.
I'm sure there's something elementary I've missed out, can anyone point it out please?!
I've worked out the solution, although it's not what's given in this article
I've replaced this line
<% render :file => 'layouts/application' %>
with
<%= render :file => 'layouts/application' %>
I'm not sure if the article is wrong, or I've found the wrong way to fix it! Please let me know!
Cheers
The original article had an error, and your solution is correct. Here's the reason:
The output of ruby code in an ERB (view) that is encased in <%= %> gets added to the HTML that's generated and sent to the browser. The output of ruby code that is encase in <% %> does not get added to the HTML. So calling <% render :partial ... %> has no effect since the result of that ruby code (fetching the partial) isn't added to the generated HTML file.
<% %> is generally reserved for conditionals and loops, as you have in the example above.
Here is a different approach to nested layouts that may come out handy.
Related
I need to use yield/content_for in <head>, but assign the value in <body>. I have found that this works fine when the value is being assigned from within a template that is being yielded to, but not one that is being rendered. Templates that are being rendered are compiled after <head>, so my value is already set in stone. Is there a way to achieve what I am trying to do?
I tried making application.html.erb look like this:
<%= render layout: 'application_template' do %>
<!-- <body> content here -->
<% end %>
and _application_template.html.erb look like:
<!doctype>
<html>
<head>
<%= content_for :my_value %>
</head>
<body>
<%= yield %>
</body
</html>
but the same problem happens, the value is nil when _application_template.html.erb is rendered.
You should be able to do the following.
In your head check if there is any content to yield and yield it if it is.
<% if content_for?(:my_value) %>
<%= yield :my_value %>
<% else %>
And then define your content somewhere in your body.
<% content_for :my_value do %>
# your contents
<% end %>
I figured out a solution.
# layouts/application.html.erb
<% content_for(:body_content) { render partial: 'layouts/body_content' } %>
<!doctype html>
<html>
<head>
<%= yield :my_value if content_for?(:my_value) %>
</head>
<body>
<%= yield :body_content %>
</body>
</html>
and
# layouts/_body_content.html.erb
# everything that used to be in <body></body> goes here and is maintained here.
This makes sure that all of the #content_for calls I need to happen will happen before <head> is compiled in my layout. It is also easier to maintain than some of the other hacks I had thought of trying.
I follow the Ruby on Rails tutorial by Michael Hartl and I'm stuck with an example that is not working for me.
I try to remove duplicate code from .erb files so that the code exists only in the application.html.erb file. With the old home.html.erb file everything works out well (when I do a GET for home the content is shown), but with the one I am supposed to use to eliminate duplicate code, no content is shown. After testing, I found out that even removing the title tag from the old file is enough to make the content dissapear.
Any ideas why that is happening? Is the tutorial wrong or did I miss something?
application.html.erb:
<!DOCTYPE html>
<html>
<head>
<title>Title | <%= yield(:title) %></title>
<title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
home.html.erb
<% provide(:title, 'Home') %>
<h1>Sample App</h1>
<p>
This is the home page for the
Ruby on Rails Tutorial
sample application.
</p>
old home.html.erb:
<% provide(:title, 'Home') %>
<!DOCTYPE html>
<html>
<head>
<title>Title | <%= yield(:title) %></title>
</head>
<body>
<h1>Sample App</h1>
<p>
This is the home page for the
Ruby on Rails Tutorial
sample application.
</p>
</body>
</html>
The problem with your layout file is that you have two <title> tags, one containing the title of your application, and one left open. If you remove the one left open, the problem will be resolved.
You should fill in the application layout in the controller. In other words, add layout 'application' to your controller. For example:
class StaticPagesController < ApplicationController
layout 'application'
def home
end
def help
end
def about
end
end
I'm trying to add a layout to the application layout. I having trouble trying to figure out all the different layout solutions. First I tried just a layout inside a layout because I didn't fully grasp what partials are or if they are layouts also? Maybe I can start with that question. What is the difference between a layout and a partial.
Here is what I have right now. I'm trying to just separate out my header code which has a navigation and some other elements into a separate layout. I want this layout to be on all views. Meaning it should be a layout inside the applications layout along with other views that are been called when their controllers are called. Which is covered in my code with the <%= yield %>. That yeild works but the :header one does not.
Application Layout app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>home</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="header"><%= yield(:header) %></div>
<%= yield %>
</body>
</html>
Header layout app/views/layouts/application.html.erb
<% content_for :header %>
<p>HEADER TEXT</p>
<% end %>
Why would the code above not work?
I also saw code like this that I tried but it gave me an error.
<%= render layouts/header %>
Can someone please explain all these different methods.
Thanks.
It's good practice to separate your header and footer into partials which you would live in the views/layouts folder as '_header.html.erb' and '_footer.html.erb' respectively.
You can then optionally wrap each partial with specific div's which is what you're trying to do with the header (you could do the same with the body too), and it would end up looking like this:
<!DOCTYPE html>
<html>
<head>
<title>home</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="header">
<%= render 'layouts/header' %>
</div>
<%= yield %>
<div id="footer">
<%= render 'layouts/footer' %>
</div>
</body>
</html>
That will do what you want it to do.
Note that 'layouts/header' and 'layouts/footer' have '' around them.
To answer your question on what is the difference between a layout and a partial, well a layout is something that will used throughout your application, such as a consistent header or footer. A partial can be a layout, but it doesn't have to be, so you can partial specific to other views across your site.
<% content_for :header do %>
<p>HEADER TEXT</p>
<% end %>
You forgot the do
So - first - The yield syntax may or may not be correct, but I've never seen it, and I don't like it. I only ever call yield once in a file.
If you want to render a header in your application template file, that's certainly possible - my advice would be to place it in your template file directly - after all, that's what template files are for. If you want to completely encapsulate your header for some reason or another in seperate files, what you need is partials. You're going to do something like this:
<body>
<%= render :partial => "shared/header" %>
<%= yield %>
</body>
Which will render your header content, stored in /shared/_header.html.erb into the layout here.
Check out this guide here for more info
Is it possible to manipulate the placeholders so that I can not only set their content, but also add/remove content in a particular order? For example:
layouts/base.html.erb (a base layout meant to be extended):
<!DOCTYPE html>
<html>
<head>
<title><%= yield :title %></title>
<%= yield :stylesheets %>
<%= yield :javascripts %>
<%= yield :csrf %>
</head>
<body>
<div class='container-fluid'>
<%= yield :header %>
<%= content_for?(:content) ? yield(:content) : yield %>
<%= yield :footer %>
</div>
</body>
</html>
layouts/application.html.erb (this is the layout I will be using for the most part of my app, it inherits from the base layout):
<% content_for :stylesheets do %>
<%= stylesheet_link_tag "application", :media => "all" %>
<% end %>
<% content_for :javascripts do %>
<%= javascript_include_tag "application" %>
<% end %>
<% content_for :csrf do %>
<%= csrf_meta_tags %>
<% end %>
<%= render :template => 'layouts/base' %>
Now I want a layout for a specific controller, which may need to add more javascript links, or maybe completely remove them. Let's say I want to add only one file after the other javascripts. So far I got this:
layouts/some_controller.html.erb (this is a layout for a particular controller, it should inherit from the application layout):
<% content_for :javascripts do %>
<script src="/assets/some_javascript_that_depends_on_jquery.js" type="text/javascript"></script>
<% end %>
<%= render :template => 'layouts/application' %>
This won't work, because it will place some_javascript_that_depends_on_jquery.js at the beginning of the :javascripts placeholder, and I need it at the end because it depends on jquery.
It would suck to have to extend the base layout directly, and keep track of any change made to the application layout to apply it to the controller-specific layout too.
What would be the recommended way to deal with this situation?
In application.html.erb, Keep the contents of content_for :javascripts in a partial
Here your partial will have
<%= javascript_include_tag "application" %>
Then, call the same partial in addition with other javascripts in other layout.
Another way,
You can call one helper which will have a hash like this:
js_files = {"application_controller" => ["js_file_1"], "some_controller" => ["js_file_1","js_file_2"]}
Now, fetch the js files and construct the javascript include tag in run time based on controller in your content for.
Hope this will be more flexible.
Sorry for not formatting.
Always keep one js file per controller.
<%= javascript_include_tag params[:controller] %>
lets take example of users controller then there will be users.js.coffee file.
If you want to have multiple js files for users controller then you can require those files inside users.js.coffee file
vi users.js.coffee
//= require 'a'
//= require 'b'
/* my extra js code will go here */
This can't be done as in other frameworks where you just extend layouts and then modify the inherited blocks at will.
Rails sort of forces you to keep it simple.
I'm following the Ruby of Rails getting started guide, and I see this code in the layout file:
<!DOCTYPE html>
<html>
<head>
<title>Blog</title>
<%= stylesheet_link_tag "application" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body style="background: #EEEEEE;">
<%= yield %>
</body>
</html>
Coming from an MVC3 background, is this the equivalent to the RenderContent() method one would invoke from the _layout.cshtml file?
The functionality is about the same in that context, yes. However, yield in general is a keyword in the ruby language, concerning blocks. You can find more information here: ruby blocks.
Building on that, you are able to provide content for different parts, using content_for(:something) and yield :something (the yield passes :something to the layout engine, the layout engine fills in the content for it).