Rails scss stylesheet per action - css

How can I render a stylesheet per action in rails?
Since my app is not the standart CRUD app, my controllers end up with a few custom routes which require very different CSS's.
So, I'm wondering, is there any way to load the css on a per action basis but still take advantage of the asset pipeline?
Thanks

create a directory for each of your controllers inside stylesheets directory and create css files corresponding to your action, then put this in you layout file
<%= stylesheet_link_tag "#{params[:controller]}/#{params[:action]}" %>

You can use controller specific assets. Just remove the *= require_tree . from application.css. And include the stylesheet the action specific stylesheet in its view by <%= stylesheet_link_tag "style.css" %> but you have to tell rails to compile them by Rails.application.config.assets.precompile = ["style.css"]. You can read more about it here. This way I guess we are using rails assets pipelines just not in default way.

Add a unique id to the body based on the controller path and action:
Helper:
def page_id
"#{controller_path.tr('/', '-')}-#{action_name}".dasherize
end
Layout:
<body id="<%= page_id %>"...
Then scope your styles to it:
/users/index.scss
#users-index {
.. page specific styles here ..
}

Related

How to properly remove bootstrap CDN from `assets.precompile` and isolate controller stylesheets

I was trying to segregate my CSS to specific controllers by compiling my assets and rendering them in my layouts via <%= stylesheet_link_tag "application", params[:controller] %>
I am using the Bootstrap (4.3.1) CDN and have this in my application.scss file:
#import "bootstrap-sprockets";
#import "bootstrap";
The problem is that when I do Rails.application.config.assets.precompile += %w( *.css ) it must be compiling bootstrap as it gives me this error:
Sass::SyntaxError in RecipeCategories#index
Undefined variable: "$alert-padding".
So I'm using this to "solve" it:
Rails.application.config.assets.precompile = [ Proc.new{ |path| !File.extname(path).in?('.css') }, /bootstrap.css$/ ]
I don't know if this is effective or best practice to prevent bootstrap from being precompiled.
I also run into the problem where a style defined in one controller's stylesheet is being loaded in the view of another until the page is refreshed. (I put the class on an element in multiple controller views to see if it was really isolated to a specific controller.)
Basically, the style in one controller's CSS file is able to be used in other controllers views until the page is refreshed, then the style is "removed" from the element in the controller view that doesn't have the style in it's CSS file.
You seem to mistakenly be precompiling the bootstrap assets via the gem and Rails' asset pipeline AND getting bootstrap from a CDN. You only need one or the other, so you can probably remove the gem and just use the CDN.

Having trouble getting page-specific CSS to work on only the one designated page in Rails

I’m using Rails 4.2.3. I want to create page-specific CSS, so I created this file
app/assets/stylesheets/profile.css.scss
and then in my “app/views/users/edit.html.erb” page, I added this at the top
<%= stylesheet_link_tag "profile" %>
This works for this page, the problem is that this style is getting included in other pages even where I didn’t specify this stylesheet designation. How do I get the stylesheet to only appear on the one page?
Thanks, - Dave
Remove *= require_tree . from application.css.scss. This line includes all the css file in all the pages
To include the controller specific stylesheet include this tag in each view
<%= stylesheet_link_tag params[:controller] %>
If you have css that you want to include across all pages you can include
*= require_tree ./common_dir in application.css.scss and create the common_dir under assets/stylesheets

Rails 4: How to exclude a CSS file from a specific view?

How can one exclude a specific CSS file (custom.css.scss) from a specific view (home.html.erb)?
Following scenario. My rails app is made up of the actual web application for which one has to sign in for to see it and the outward facing landing page.
The CSS for the web application lives inside a file called custom.css.scss.
For the landing page I created a new CSS file called static_pages.css.scss.
Now, the problem obviously is that Rails pulls in all stylesheets and applies them to all views:
*= require_tree .
*= require_self
However, now my landing page is being messed up by the custom.css.scss file which contains the app-specific CSS and vice-versa.
Since my landing page is simply a one-pager, the ideal solution would be to simply exclude custom.css.scss from my home.html.erb file which represents the landing page.
How can I achieve this?
I have found various topics on this problem for but can't make sense of it. Some look to simply inject, some look to exclude.
Help is very much appreciated.
Find this kind of line in your template:
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
It actually does the magic, both of custom and static css was included to application.css
Excluding something is weird, for css we usually use selector to identify which elements will be effect to.
My suggestion to achieve your case is:
Add specific class/id which identifies controller/action
For example, I add this kind of code to my layout template:
<body id="<%= controller_name %>_body">
So every view now has id for its body
Modify custom css to apply for all, except landing page. For example my landing page has body's id: landing_page_body
In custom.css.scss
body:not(#landing_page_body) {
// My css here apply for all except for #landing_page_body
}
If you wanted to include a specific stylesheet on a per-page basis, you'll have to create & compile it separately, calling it as you need:
#config/initializers/assets.rb
#app/assets/stylesheets/application.css
/*
*= require_tree .
*= require self
*= stub custom
*/
#app/assets/stylsheets/custom.css
...
This would allow you to specify when you're going to call the stylesheet:
#app/views/layouts/application.html
<%= stylesheet_link_tag :application, (:custom if controller_name != "landing") %>
This will only load the custom stylesheet if you're not using the landing controller.

Controller specific stylesheets in rails 3: Inheritence

Firstly,I'm a newbie to rails.I'm working on a rails website. It has three controllers namely
application_controller,static_pages_controllers and users_controller. They all have their respective css (scss) files in app/assets/stylesheets/ (application.css and users.css.scss)
except static_pages_controllers and also has a custom.css.scss for overall layout or common elements.I used controller specific stylesheets as mentioned
here
My questions are:
1) does the css rules in custom.css apply to all the controllers views except for those I have defined explicitly in seperate controller css?
2) if yes,then I have a rule defined in both custom.css.scss and users.css.scss
custom.css.scss - body { background-color:color1;}
users.css.scss - body { background-color:color2;}
but still views in both static_pages_controllers and users_controllers show background color2. where am I going wrong? only views in users_controller must show color2 and static_pages_controller must show color1.
The Rails guide on how to use the asset pipeline doesn't quite tell the whole truth here. It says:
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] %>.
Now, you could do as they suggest and load specific stylesheets for each controller, but it does not work as they suggest out of the box. The neglect to mention a few things you must do.
You need to remove the //= require_tree . directive from application.css, which, left in place, will load every other asset in the folder. This means that every page would load users.css, and if you added the controller-specific stylesheet line as in their example, it would load the controller stylesheet twice.
You would need to tell Rails to precompile the individual files. By default, all *.css files besides application.css are ignored by the precompiler. To fix this you'd have to do edit your config to do something like this:
# in environments/production.rb
# either render all individual css files:
config.assets.precompile << "*.css"
# or include them individually
config.assets.precompile += %w( users.css static_pages.css )
Finally, as instructed by the Rails guide, you'd need to change your stylesheet includes to look something like:
<%# this would now only load application.css, not the whole tree %>
<%= stylesheet_link_tag :application, :media => "all" %>
<%# and this would load the controller specific file %>
<%= stylesheet_link_tag params[:controller] %>
However, the above may not be truly the best practice. Sure, sometimes you might want individual stylesheets, but most the time you probably just want to serve your style bundle so the client can cache one file. This is how the asset pipeline works out of the box, after all.
Besides that, if you were to just add override rules in your controller specific stylesheets, then you're creating a load-order-specific tangle of styles right out of the gate. This... is probably not good.
A better approach might be to namespace the styles in the controller sheets, something like this:
// in application.css (or some other commonly loaded file)
background-color: $color1;
// in users.css.scss
body.controller-users {
background-color: $color2;
}
// and so on...
Then in your layout, add the controller name to the body class, like:
<body class="controller-<%= params[:controller] %>">
In this way, your styles are resolved by namespace, not just load order. Furthermore with this solution you could still go ahead and load separate controller-specific stylesheets if you desire, or you could forget about that and just let everything be compiled into application.css as it would be by default. All the styles would be loaded for each page, but only the controller-specific styles would apply.
In Rails 4.x
you have to add these lines in config/environment.rb
config.assets.precompile << "*.css"

Can I use CSS assets and the public folder in the same app?

I have a legacy application that I'd like to migrate to use the Rails 3 asset pipeline. I have upwards of 100 stylesheets which are imported on a template by template basis using a
content_for :stylesheets
block.
Compiling them all into a single stylesheet is not currently a goer as the code was written to expect only certain stylesheets on certain pages, so for example the login page imports a stylesheet which redefines article form. It would not be good to redefine this on all pages.
Is there a way to migrate slowly to the assets pipeline having the app look first for a compiled asset, and then having it failover to the public/stylesheets directory?
If you want to do this "right", one thing that would not take a huge amount of effort would be to put a class name on your <html> or <body> tag and wrap the contents of your CSS files with a selector. For example, I use something similar to the following in my ApplicationController.
before_filter :body_class
def body_class
controller_name = self.class.name.gsub(/Controller$/, '')
if !controller_name.index('::').nil?
namespace, controller_name = controller_name.split('::')
end
#body_classes = ["#{controller_name.underscore}_#{action_name} ".downcase.strip]
#body_classes = ["#{namespace.underscore}_#{#default_body_classes.join}".strip] if !namespace.nil?
end
Then, in my layout I have something similar to this
<body class="<%= #default_body_classes.join(' ') %>">
Next, you could change the extension for all of your stylesheets to .css.scss. Put them all in the new app/assets/stylesheets directory. To include them quickly (though possibly out of order), add
/*
* =require_tree .
*/
to the top of a new app/assets/application.css.scss file. Just include this one application.css file in your layouts.
<%= stylesheet_link_tag "application", :media => 'screen' %>
Finally, spend some time going through your stylesheets wrapping the entirety of each document with the appropriate body class. For example, if you have a stylesheet specific to some User::Admin controller's signup action, you would wrap the entirety of that stylesheet with
.user_admin.signup {
/* Your stylesheet's content here */
}
Sass will prefix all nested content properly with the .user_admin.signup class that will be appended to your <body> tag when that action's being rendered.
I realize this isn't really an intermediate fix as you're looking for, but following steps similar to this you should be able to get 95% of the way there with not much effort, and it will be done "right".

Resources