How would I display different headers in Rails in application.html.erb? - ruby-on-rails

How would I display different versions of headers in Rails in my application.html.erb view? For instance, for my landing page, I have a pretty big header that includes a callout and some sign-up and sign-in buttons. For other static pages, I have a normal small header with a logo and a few links to the right. And for my dashboard when users log in, it will look a little different as well.
How can I display certain headers in an if/else statement where Rails will output the different versions of headers based on the current url or view in my application.html.erb?

To answer your question with an example this is what you may want to do.
Rails has a provision to use nested view templates using the content_for and yield tags.
Do the following thing to achieve what you want -
In app/views/layouts/application.html.erb - Add a ternary expression which acts as a if else. While rendering the views rails will look for a <% content_for :custom_header do %> in the view templates. If it doesn't find that it will render the partial app/views/layouts/_default_header.html.erb instead.
<html>
<head>
<title><%= #page_title or "Page Title" %></title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<!-- Code to conditionally load a header -->
<%= content_for?(:custom_header) ? yield(:custom_header) : render :partial => "layouts/default_header" %></div>
<!-- For the body -->
<%= yield %>
</body>
</html>
Now since you say that most pages will have a static small header, save the html code for that in a partial under app/views/layouts/_default_header.html.erb.
In you landing page (for example the the view app/views/welcome/index.html.erb) you can use the content_for tag with the identifier :custom_header that we have used in the application.html.erb
Add the following in your landing page.
<% content_for :custom_header do %>
<div class="custom-header">
<!-- Your complex header with sign in and signup links... -->
</div>
<% end %>
The ternary operator in the application.html.erb will pick up this content from the content_for tag in the landing page and insert the content in place of the yield(:custom_header).
Hope this helps.

It sounds like you may want to use a nested layout.

Related

Single template in Rails application

I'm trying to use Rails with Angularjs. Angular will do all the client side work while Rails controllers suppose to handle requests to list and modify information (in Database).
I have a simple template in views/layouts/application.html.erb:
<!DOCTYPE html>
<html>
<head>
<title>SomeApp</title>
<%= stylesheet_link_tag "application", :media => "all" %>
<%= stylesheet_link_tag "vendors", :media => "all" %>
<%= csrf_meta_tags %>
</head>
<body>
<div id="wrapper" ng-app="app" ng-controller="AppCtrl">
<div ng-controller="SomeApprCtrl">
<%= render 'header' %>
<div ng-view=""></div>
<%= render 'footer' %>
</div>
</div><!-- End on wrapper -->
<%= javascript_include_tag "application" %>
</body>
</html>
This template does everything i need to start Angular. But i need to put something in Rails routes. I need to define controller and action. Say something like this:
root :to => 'main#index'
And this mean that I need to define controller Main with only one empty method index and totally empty template file in views/main/index.html. How can i avoid appearance of this empty useless files?
I was thinking of using root :to => 'application#index' and define empty index method in ApplicationController but since this controller is basic for inheritance to all other controllers i don't want them to have any crap. Also this approach does not solves problem with empty index.html template
While it is empty the controller is actually handling a lot by convention. It automatically displays the index.html.erb view, and since the layout hasn't been specified it wraps it in the application.html.erb layout.
So while the file may be sparse there's a lot going on behind the scenes.

Yield layout in rails

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 <%= yield %> the Rails equivalent of MVC3's RenderContent()?

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

How to assign different stylesheets in a rails project?

I have a stylesheet, application.css defined in layouts/application.html.erb:
<%= stylesheet_link_tag "application" %>
However, there's a section of the site where the views will use a completely different stylesheet, dashboard.css which I've defined in its index.html.erb:
<head>
<title>My title</title>
<%= stylesheet_link_tag "dashboard" %>
..
Unless I remove the stylesheet_link_tag in the application layout file, there are conflicts which make the dashboard view weird. If I move the application layout stylesheet tag to a _header.html.erb partial which is rendered with every view in the non-dashboard section like below, it doesn't work. How must I call them?
<%= stylesheet_link_tag "application" %>
<header>
<div id="headercontainer">
..
you should use a yield statement in your application.html.erb in the head element as such:
<head>
<%= yield :head %>
</head>
then in your view, you would use a content_for tag:
<% content_for :head do %>
<%= stylesheet_link_tag "dashboard" %>
<% end %>
also read the rails docs on nested layouts. it'll teach you how to get fancy with this paradigm
Create a separate layout for your dashboard, with specific stylesheets.
If you want customized stylesheet for one of your controllers (and all of its actions), it's quite easy to do. Create a layout with matching name, that is, for your users_controller, template name should be users.html.erb.
Also you can specify any layout for controller.
class UsersController < ApplicationController
layout 'some_layout'
end
If you want custom stylesheet only for some actions, specify corresponding layout in call to render.
def dashboard
# some logic here
render :layout => 'some_layout'
end
I would suggest you define a second layout for dashboard (app/views/layouts/dashboard.html.erb). From that layout link to the dashboard stylesheets. Then use that layout from your dashboard views or controllers.
Oh just use some if conditions to link different stylesheets in the same layout:
<%= stylesheet_link_tag(dashboard_views? ? "dashboard" : "application") %>
Just implement dashboard_views? helper method to return true or false based on your views.

How to include a css or javascript in an erb that is outside the layout?

Sorry for the slightly noobish question, as I am writing my first rails app.
I get the idea of the layout view, but if you are using them, is there any way to include a view specific js or css file? For example, I have layouts/products.html.erb, and for products/edit.html.erb I want products_edit.css, but I don't want that css for all product views, what is the best practice to accomplish that?
If you have a generic edit.css file, I would suggest an if in your layout
<%= stylesheet_link_tag 'edit' if params[:action] == 'edit' %>
Otherwise you can use content_for with a yield to add additional tags into the head.
layout.html.erb
<head>
...
<%= yield(:header) if #content_for_header %>
</head>
products/edit.html.erb
<% content_for :header do -%>
<%= stylesheet_link_tag 'edit_product' %>
<% end -%>
You can add a stylesheet tag inside the head tag of the layout by doing something like this:
layouts/products.html.erb:
<head>
...
<%= yield :css %>
...
</head>
products/edit.html.erb
<% content_for :css do
stylesheet_link_tag 'products_edit'
end %>
You can't if your </head> tag is in your layout.
You may want a different layout for that controller action. Like this on the render:
render :action => "index", :layout => "some_other_layout
Also you can set a different default layout for a whole controller with this line in the controller class:
layout "some_other_layout"
Check the API docs, there's some complex things you can do with conditionals on that layout method.

Resources