By default, (at least, using scaffolding), Rails adds links to all stylesheets in the /app/assets/stylesheets directory. I'd like to have multiple smaller stylesheets for organization, but only need to link to one that imports the rest in order to stay organized yet minimize HTTP requests.
Is there a way to disable this auto-inclusion, whether by configuring the asset pipeline or changing how they're included in the layout itself?
FWIW, I'm including the main stylesheet from application.html.haml using stylesheet_link_tag "application".
You can do this by modifying your application.css(.scss) file.
In that file there will be the following line:
require_tree .
Simply remove that and replace it with the includes you require.
application.css
require file1
require nested/folders/file2
Then you can have another file
main.css
require file2
require file3
And include them separately:
stylesheet_link_tag "application"
stylesheet_link_tag "main"
The stylesheet_link_tag can take an array too, if for some reason you want the css files to load in the same place, but with separate HTTP requests.
stylesheet_link_tag ["application", "main"]
The files with the requires are called manifest files.
Related
I am reading rails guides documentation for asset pipeline.
It states that coffeescript page specific generated files
are by default ready to user if there is a require_tree directive on the manifest.
This is not working with me I have to do include this
<%= javascript_include_tag params[:controller] %>
on the specific controller.
What am I missing ?
The asset pipeline will compress all of your JS into a single file, application.js. In order to call JS for a specific page, you will need to organize your JS by controller and action. There is a gem, RailsScript that does this automatically and it's compatible with Turbolinks which can give you a single page application feel.
RailsScript only takes a few minutes to learn, https://github.com/gemgento/rails_script.
A specific example using rails script:
# app/assets/javascripts/users.js.coffee
window.App ||= {}
class App.Users extends App.Base
show: ->
alert('The users#show action!')
I think you are misunderstanding the asset-pipeline in general. It doesn't load the javascript-files individually, but rather all the .js.coffee files will get compiled into one big js-file, which you have to include in your views/layout like this
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
If you want some js-code that is only available in one view, you definitely should not include that into the asset-pipeline.
Not sure if I've misunderstood your first paragraph, but I think what the line means is that if your application.js manifest contains a line like:
//= require_tree .
Then yes indeed, page specific javascript, or coffeescript will be loaded, not only for that specific page, for for all pages. If you want to constrain assets to certain pages like you've described, you will need a file located in app/assets/javascripts/ with the pluralized name of the controller, and .js.
I would personally create this as another manifest for that specific page, that way I can load multiple assets. Lets say you have a controller called UsersController, with various assets used by that controller's views. What you then need, in order for the line you wrote in your question to work, is a .js filed users.js or users.js.coffee in the app/assets/javascript directory.
Alternatively, to maintain the naming convention, I do something like this:
<%= javascript_include_tag "application-#{params[:controller]}"%>
and then of course name my file appropriate (application-users.js).
Also, when you do this, you'll want to stop your page-specific assets from loading for all controllers. Simply remove the //= require_tree . line and replace it with explicit //= require lines as needed.
Here's a way to do page-specific javascript in rails.
Install the jquery-readyselector.js plugin. (It's 18 lines)
a. Copy the contents of https://raw.github.com/Verba/jquery-readyselector/master/jquery.readyselector.js
b. Paste the contents to a new file at assets/javascripts/jquery_readyselector.js
c. Require jquery-readyselector
// assets/javascripts/application.js
//= require jquery_readyselector
//= require_tree .
Create CSS classes so we have a way to reference each page individually.
<%# views/layouts/application.html.erb %>
<body class="<%= controller_name %> <%= action_name %>">
Now we can scope our javascript to our page using CSS.
// assets/javascripts/posts.js
$(".posts.index").ready(function() {
});
Due to a specific setup, I would like to split the compiled stylesheets in two files. This is because (a part of) the CSS is needed for a Java application which can parse the CSS, but it is a bit buggy and can't handle some css-(hack)-syntax. Because I am unable to modify this Java application, I want to feed it only the CSS which it needs and of which I can make sure it is correct.
So, normally the assets pipeline would produce just one '/assets/application-[..].css' file. It would to let it also generate '/assets/custom-[..].css', based on a file selection I make. This still can be pre-compiled.
Is there a way to do this? Although I understand this is not the ideal setup..
To tell rails about additional files you wish to have precompiled, you can add them to the config.assets.precompile setting.
config.assets.precompile += ["other_application.css"]
You only see application.css in your HTML because that's the only file you're including
<%= stylesheet_link_tag "application" %>
If you have some custom.css.scss in your apps/assets/stylesheets directory, it will be compiled just like application.css.
For example, I might have
- _common.css.scss
- application.css.erb.scss
- other_application.css.erb.scss
in app/assets/stylesheets. In the top of the non-partial files I will put
#import "common";
to include _common.css.scss. I can now reference either stylesheet independent of one another in a layout.
<%= stylesheet_link_tag "application" %>
# or
<%= stylesheet_link_tag "other_application" %>
Using Rails 3.2.1
I created a simple controller called Home using the command:
rails g controller Home index
And it created a new controller and view for me:
Notice how there are two stylesheets, one "Application" and one "Home". I can't find any documentation to support this assumption but I'm guessing you put styles that will only be applied to the "Home" views, in the Home.css.scss file, correct?
So as a test, I added in some global styles to Application.css.scss.erb and ran the application.
The styles applied as expected.
Next, I added in some rules to the Home.css.scss file and I visited a "Home/index" view, yet the style in that file wasn't attached, neither as a seperate CSS reference link, or even appended to the single Application.css.scss file. This is highly confusing to me, since the comments say:
// Place all the styles related to the Home controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
Why aren't the rules written in Home.css.scss applied to my website?
It can work this way and Marek is quite correct, the answer is in the guide.
In the introduction to section 2.1:
For example, if you generate a ProjectsController, Rails will also add a new file at app/assets/javascripts/projects.js.coffee and another at app/assets/stylesheets/projects.css.scss. You should put any JavaScript or CSS unique to a controller inside their respective asset files, as these files can then be loaded just for these controllers with lines such as <%= javascript_include_tag params[:controller] %> or <%= stylesheet_link_tag params[:controller] %>.
So to set your application up to load controller specific stylesheets:
First, disable the default loading of all stylesheets by removing any extra requires in the application.css manifest.
Typically you'll see an entry like this:
*= require_tree .
If you still want to load some common css files, you can move them to a subdirectory and do something like this:
*= require_tree ./common
Second, In your application's layout add the suggested stylesheet_link_tag eg
<%= stylesheet_link_tag "application", :media => "all" %>
<%= stylesheet_link_tag params[:controller] %>
In this example we first load the application css file, we then load any css file that matches the current controller name.
I've solved this problem with a simple solution. I add to body the controller name as a class, editing views/layouts/application.html.slim:
body class=controller.controller_name
Or views/layouts/application.html.erb:
<body class="<%= controller.controller_name%>">
And then in my css I just use body.controller_name as a namespace:
/* example for /users/ */
body.users {
color: #000;
}
body.users a {
text-decoration: none;
}
For small projects I think it's fine.
I don't think it works that way (Home.css being applied only to Home controller actions). The different files are just for separation, to make it clearer what are the CSS rules describing. You can read this guide about the asset pipeline. I'm guessing you altered the default application.css.scss and removed the line importing all CSS files from app/assets/stylesheets.
TL;DR:
Ignore the comment, it's not made by Sass. But put:
#import "*";
into your application.css.scss file, and it will automatically import all the controller scss files.
Full read:
Disclaimer: This is my current understanding of the asset pipeline flow with and without Sass.
I think this comment is written by the standard Rails Asset pipeline (sprockets), and not by Sass:
// Place all the styles related to the Home controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
The standard pipeline will handle scss files but doesn't presume an application.css.scss file. But if you create such a file with Sass, then Sass will compile it to the application.css file.
If you use the normal Rails asset pipeline, without Sass, then sprockets would load the css file into the application.css file automatically (if that file has the default *= require_tree . line in it).
When you use Sass, with an application.css.scss file, Sass will compile this file into a application.css file. (I assume it would overwrite or take precedence over any application.css file you already had).
To get your home.css.scss file (and other controller files) automatically included, put this line into your application.css.scss file:
#import "*";
For reference, see this question:
Is it possible to import a whole directory in sass using #import?
I was wondering if there was a way to ignore a css file from being added to the manifest application.css file.
The reason why I want to do this is that I have two versions of the site, a mobile version, an an web version. The mobile version's css is currently being added to the manifest, and messing with the style of the main page.
Is there anyway to configure the manifest file to exclude a certain css file?
Remove the require_tree directive and add just the files you want, in the order you want them to application.css. Leave out the mobile CSS file.
To access the mobile CSS file you need to add it to the precompile list in
production.rb:
config.assets.precompile += ['mobile.css']
This will allow you to use the standard rails helper to access the mobile css:
<%= stylesheet_link_tag "mobile" %>
as distinct from the application.css file.
One tip for these situations is that you can share CSS files between manifests. For example, if you have a CSS reset in a separate file this can be added to both manifests (assuming you make the mobile css a manifest too).
What I ended up doing was creating subdirectories under app/assets/stylesheets called app/assets/stylesheets/web and app/assets/stylesheets/mobile
Then place an application.css with the standard:
/* ...
*= require_self
*= require_tree .
*/
inside each of your new web and mobile folders. Then to access them:
# just use this
<%= stylesheet_link_tag "web/application", :media => "all" %>
# or this as needed
<%= stylesheet_link_tag "mobile/application", :media => "all" %>
How can I include specific JS or CSS files (by convention ?) with Ruby Rails 3.1 ?
I have a view :
views/project/index.html.erb
And I want to include a specific javascript file for this page. I put it in
assets/javascripts/project/index.js
Same for another view :
home/index.html
Thanks
In the application.css and application.js file, be sure to remove the line \\= require tree.
Then, manually list all the css/js files you want included in each manifest file, for example:
// application.js
//= global.js
//= everywhere.js
Then, I would setup a yield in your header or your closing body tag for your application layout file, for instance (in haml)
%head
%title Some Page
= stylesheet_link_tag 'application'
= yield :stylesheets
Then in your particular view, say _example_partial.html.haml, do this:
- content_for :stylesheets do
= stylesheet_link_tag 'example_partial'
-# the rest of your view goes here
You do the exact same thing with Javascript files, just using javascript_include_tag instead of stylesheet_link_tag.
This will let you quickly and easily assemble view-specific javascript / css payloads. There may be a more sophisticated way to handle this using the asset pipeline, but I would suggest that if the asset pipeline is already minifying and merging you major stylesheets that this kind of +1 css / js file per view is not going to cause a major performance hit. Just try to make sure you don't overdo it with dozens of separate files loading into a single view.