This is a question that several people have asked before, but none of the questions were quite asked or answered in a way that I found helpful, so I'm writing the question and answer that I would have found helpful.
I have a Rails 3.1+ app using the asset pipeline. There's one specific action that I want to have use different CSS. (In my specific case, I have a page that is intended to be printed, so it truly needs completely different CSS and does not need any Javascript.) Currently, I have only one application-specific CSS file. How do I add the new CSS file and direct the asset pipeline to use my file?
For example, right now, my app/assets
looks like
app/assets
/javascript
application.js
custom.js.coffee
/css
application.css
custom.css.scss
I want to add a print.css
file that is used by the view of a specific action. This view will not use the application.css
file. How do I add print.css
?
I found this blog post to be very helpful: http://blog.seancarpenter.net/2012/11/05/page-specific-javascript-with-the-asset-pipeline/. My answer paraphrases what this blogger already wrote and fills in a few missing details.
First, it's important that you've read and understood the Rails Guide to the Asset Pipeline. Unfortunately, this guide doesn't clearly explain how to add action-specific assets, but it does cover some concepts you need to know. Make sure you understand these ideas:
require
, require_tree
, and require_self
to indicate which files are compiled together.rake assets:precompile
to produce the compiled, minified assets in the public
directory.These ideas are the minimum "need-to-know" pieces of information about the asset pipeline. If you don't already understand these ideas, you don't have an "expert or enthusiast" level of knowledge about the pipeline, and unfortunately, SO isn't the right place to learn this stuff. Fortunately, the the Rails Guide to the Asset Pipeline is a short 15-minute read and can get you up to speed quickly if you need it.
Second, these are the changes you need to make in order to ensure that the asset pipeline correctly sees and handles your new print.css
file.
Follow these steps:
print.css
file to app/assets/css
.print.css
. You need to do this, even though you only have a single CSS file you're adding. This is an easy step:print.js
to app/assets/javascript
.print.js
://= require print
This will be the only line in the entire print.js
file. If I understand correctly, Rails expects manifest files to have the file extension .js
, which is why we aren't using print.css
as the manifest file.
print.js
manifest. Add the following line in your config/application.rb
file:config.assets.precompile += %w( print.js )
application.js
manifest includes the line //= require_tree .
which means that it will include your print.css
file. This will cause your print.css
styling to affect your entire site, not just the single view. There are two ways of dealing with this:application.js
and print.js
do not share any assets, you can use the stub
command in your application.js
to exclude the assets used in print.js
. What this does is instruct application.js
to remove any of the assets that print.js
references from its own list of referenced files. Our modified application.js
looks like:(snip...) require_tree . stub print
See this answer for more information.
print.js
and application.js
files share some assets, you'll need to move all of the assets used by application.js
into subdirectories. I didn't do this myself, so I'm not the most help in this area. Look at this answer for instructions.Now we have included print.css
in the asset pipeline. We now need to direct Rails to use print.css
in your specific view.
Let's say your action is in the reports
controller, and that the action is named print_reports
. This means we have a reports_controller.rb
file and a print_reports.html.erb
(or .haml
) file. We need to make several changes to these files.
app/views/layouts
. Perhaps call it print.html.erb
. We'll use this new layout for your print_reports.html.erb
file. Set it up as you desire. For a page intended to be printed, this will likely be very simple, such as<html> <head> <title="Print"> </head> <body> <%= yield %> </body> </html>
Using a separate layout the disadvantage that it's difficult to keep this layout and the layout used by the rest of the application in sync, but if you are using separate CSS files for the action, it's unlikely that you want the layout to be the same anyway.
stylesheet_link_tag
in the layout's header pointing to your print.css
:<html> <head> <title="Print"/> <%= stylesheet_link_tag "print" %> </head> <body> <%= yield %> </body> </html>
layout 'print', only: [:print_reports]
to your controller:class reports_controller < ApplicationController layout 'print', only: [:print_reports] #snip
See this question for more information and a few different approaches.
At this point, when you run the app, your print_reports
action should be using print.css
correctly!
Remember to run rake assets:precompile
before deploying on the server.