26

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?

Sheharyar
  • 73,588
  • 21
  • 168
  • 215
Matt Briggs
  • 41,224
  • 16
  • 95
  • 126

3 Answers3

47

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 -%>
Dave Powers
  • 2,051
  • 2
  • 30
  • 34
Samuel
  • 37,778
  • 11
  • 85
  • 87
  • I'm not sure you want '<%=' on the stylesheet_link_tag line. You don't want to output that on the edit view. – erik Jan 26 '09 at 16:36
  • Yes you need it, the views use a helper called capture which takes a block, this helper will redirect all output to a variable which is then rendered in a different location. So my solution gives you more flexibility and feels more natural. – Samuel Jan 26 '09 at 16:39
  • 7
    In Rails 3.0, you need to use `if content_for? :header`, not `@content_for_header` – Natan Yellin Nov 21 '11 at 09:34
  • In Rails 5 worked for me without `if @content_for_header` – Roman Pushkin Aug 26 '17 at 05:43
10

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 %>

William Drury
  • 163
  • 2
  • 8
erik
  • 6,406
  • 3
  • 36
  • 36
-7

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.

Otto
  • 18,761
  • 15
  • 56
  • 62
  • -1, you are wrong. Using yield(:header) and content_for :header you can specify additional content for the head tag. – Samuel Jan 26 '09 at 16:33
  • That doesn't change the fact that the rest of it is perfect legitimate solution to the problem. – Otto Jan 26 '09 at 17:28
  • No, but it violates the DRY principle that rails loves so much. – Samuel Jan 26 '09 at 17:37
  • How so? I can resolve duplication in the layouts via partials, if there's enough of it. I'd say your solution pushes too much knowledge of the layout down into the templates that ought to be ignorant of what they're contained in, aside from a clearly delineated contract. – Otto Jan 26 '09 at 17:45
  • 1
    Using a different layout just to add one css file will introduce duplicated code in the layout. When you can add functionality that is very powerful and very DRY. And you really shouldn't be so petty about the down vote, don't take it personally. – Samuel Jan 26 '09 at 18:08
  • Again, if there's a lot of duplication between layouts, I can use partials to resolve it. And I didn't down vote you. – Otto Jan 26 '09 at 18:38