Using twitter bootstrap with rails assets pipeline and less - ruby-on-rails

How to integrate properly twitter-bootstrap-rails gem with the assets pipeline?
I've followed installations steps and currently I have this application.css
*= require_self
*= require bootstrap_and_overrides
And then in bootstrap_and_overrides.css.less I'm importing other controllers stylesheets in order to make them work with my variables defined in the overrides file and to be able to use bootstrap mixins within the controller specific stylesheets in <controller-name>.css.less files. Currently I'm doing this:
# in bootstrap_and_overrides.css.less
// generated code ...
// Your custom LESS stylesheets goes here
//
// Since bootstrap was imported above you have access to its mixins which
// you may use and inherit here
//
// If you'd like to override bootstrap's own variables, you can do so here as well
// See http://twitter.github.com/bootstrap/less.html for their names and documentation
//
// Example:
// #linkColor: #ff0000;
#linkColor: #ff0000;
// import all other stylesheets
#import 'home.css.less';
#import 'users.css.less';
// and so on, once for every controller
// in home.css.less
#foobar {
.border-radius(30px); // bootstrap mixin
color: #linkColor; // inherited variable
}
However in this way I'm losing the assets pipeline and I can't see individual stylesheets anymore in development mode. Is there any way to make twitter-bootstrap-rails working with sprockets?

Think this issue on github explains your question. (I know it's for sass, but the explanation should be valid anyway)
In short, using sprockets will compile each file individually which means that you can't use variables and mixins defined by the twitter bootstrap framework. So I guess the answer is no :)

Related

Rails 4.2: Custom Helper for SCSS Manifest in Engines

Our application is a collection of 3 engines that make up our base gem. Other plugin gems, written specifically for our base gem, can be used to add functionality to the base.
Currently we have 2 custom sprockets directives and 1 custom Sass importer that attempts to pull in SCSS files from these plugins dynamically into the base manifest. A contrived example looks something like:
//= depend_on_gemfile # mimics default "depend_on" functionality
//= depend_on_stylesheets # mimics default "depend_on" functionality
...
#import 'engine/namespace/settings/global';
#import 'engine/namespace/settings/colors';
#import 'engine/namespace/settings/fonts';
#import '[engine-plugins]/namespace/settings'; # mimics Sass Filesystem importer
...
To be clear, this works. We're having problems with the way Sass is caching the files, that is a bit too complicated to get into and not really my goal at the moment.
The point is that we realized that removing the custom Sprockets directives and Sass importer, in favor of using a Rails helper, would also solve our problem, since the ERB would be compiled before the SCSS, we'd be able to find and format all of the paths needed in all included plugins into a string and dump it out into the manifest. Something like:
#import 'engine/namespace/settings/global';
#import 'engine/namespace/settings/colors';
#import 'engine/namespace/settings/fonts';
<%= load_plugin_stylesheets_for('settings'); %>
...
This seems like a much more simple solution, since all we are doing is finding each path and converting those paths to strings.
The problem seems to be that Rails helpers are outside of domain of Sprockets entirely.
I've found some resources, but they all seem to pertain to Rails 3.
Add custom methods to Rails 3.1 asset pipeline?
https://github.com/rails/rails/issues/3282
I'm curious if anyone has had this problem with Rails 4, if they solved it and how. Or if I'm just thinking about this all wrong and there is a better way to approach the problem without a similar over-complication like we had before.
TL;DR
I'd like to use regular Rails helpers inside of a Sprockets manifest file. The Rails version is 4.2.4. We're running engines. Is this possible?
EDIT:
This comment answered my question.
After implementing this solution in an initializer within our engine.rb file, all of the Rails ActionView Helpers were available, including my custom written helper.
We had a similar issue a while ago.
application.scss (within gem) looks like this:
/*
*= require_tree .
*= require_self
*/
#import "c3.min";
#import "analytics";
and gemspec contains line for including all the code from app folder.
Gem::Specification.new do |s|
s.files = Dir['{app,config,db,lib}/**/*', 'MIT-LICENSE', 'Rakefile', 'README.rdoc']
end
Be sure to check that you don't have any caching enabled in env files as well.

How should I go about managing sass code when using bootstrap-sass?

The documentation says:
Import Bootstrap styles in app/assets/stylesheets/application.scss:
// "bootstrap-sprockets" must be imported before "bootstrap" and "bootstrap/variables"
#import "bootstrap-sprockets";
#import "bootstrap";
bootstrap-sprockets must be imported before bootstrap for the icon fonts to work.
Make sure the file has .scss extension (or .sass for Sass syntax). If you have just generated a new Rails app, it may come with a .css file instead. If this file exists, it will be served instead of Sass, so rename it:
$ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
Then, remove all the //= require and //= require_tree statements from the file. Instead, use #import to import Sass files.
Do not use //= require in Sass or your other stylesheets will not be able to access the Bootstrap mixins or variables.
But if I do as they say, my other stylesheets won't be included automatically, as they did before that. Should I include every stylesheet explicitly in layout? AFAIU, that would also make me have separate stylesheets in production environment, instead of one as it would have been without bootstrap-sass.
There are several things here. First, by default each stylesheet is served in separate http request in development, and in one request in production (they are precompiled into one file). If we follow the docs, we'll end up having one request in development as well, which would negate performance benefit of compiling only the file that has changed. If we don't, we might end up having bootstrap several times in our stylesheets. In case we need some variables or mixins in several stylesheets.
So I suggest having it this way:
application.sass (do note that I put require_self before require_tree .):
/*
*= require_self
*= require_tree .
*/
// import bootstrap once
#import "bootstrap-sprockets"
#import "bootstrap"
.d1
text-align: center
welcome.sass:
// in other files import only some particular partials
#import "bootstrap/variables"
#import "bootstrap/mixins"
.d2
text-align: right
But if I do as they say, my other stylesheets won't be included automatically, as they did before that.
Yes, you a right.
1) You shouldn't remove your require directives from application.scss. They don't want to use require directives because in this case you don't have ability to use SASS variables and mixins inside of included files.
2) Just rename application.css to application.scss. They want it because in this case you will have ability to use #import directives inside application.scss file. This is mean that you will have ability to use SASS variables and mixins inside of included files.
Should I include every stylesheet explicitly from layout?
No, just leave them in application.scss
AFAIU, that would also make me have separate stylesheets in production environment, instead of one as it would have been without bootstrap-sass.
No, you will use one application.scss in different environments.

CSS require Syntax

I have required CSS stylesheets many times in many of my RubyOnRails applications, and actually i need a few things demystified.
What is the difference between:
//=require mystyles
and
*=require mystyles
Both seem to work, so what is the difference?
And is this a part of the asset pipeline or a part of SASS or just plain CSS?
The two examples you gave are exactly the same for stylesheets, however the //= syntax is the only one that works for Javascript. You also need a standard CSS comment at the start (/*) and a close comment (*/) at the end of the require block to make it ignored to anything but the asset pipeline:
/* ...
*= require mystyles
*= require_self
*/
These require directives are only part of the asset pipeline, not CSS or SASS. To include a stylesheet for CSS or SASS, you would use a #import rule as Blieque stated in his comment.
Check out the manifest files and directives section of the Asset Pipeline guide on the Ruby on Rails guide site for a more detailed explanation of the difference. There is also a warning given there that might be of interest:
If you want to use multiple Sass files, you should generally use the
Sass #import rule instead of these Sprockets directives. Using
Sprockets directives all Sass files exist within their own scope,
making variables or mixins only available within the document they
were defined in.
There is no difference, as long as it's a valid comment line, it'll work :)

How can I get Compass to automatically import all stylesheets in app/assets/stylesheets?

I'm trying to add Compass to my Rails 3.2 app, using compass-rails. How can I get it to automatically import all of the stylesheets in app/assets/stylesheets? At the moment I have to manually do #import 'filename'; in application.css.scss for each one.
Put all your scss files (except application.css.scss) in a different folder:
/application.css.scss
/all/hello.css.scss
/all/hi.css.scss
application.css.scss file like below will work.
#import "compass";
#import "all/*";
For bundling stylesheets, use the asset pipeline
If you're using the asset pipeline, this should happen automagically with:
/*
* In application.css
*= require_tree .
*/
Docs: http://guides.rubyonrails.org/asset_pipeline.html#manifest-files-and-directives
The important caveat is "Using Sprockets directives all Sass files exist within their own scope, making variables or mixins only available within the document they were defined in."
For mixins & vars, have your imports in one place, then import once
If you're heavy on the functions, try having a file like app/assets/stylesheets/base.css.scss that contains #import directives (wildcard or not) for all your mixin and var files. Then you only need to #import "base" once for every stylesheet and can still bundle your css using sprockets directives.

Use Rails 3.1 Asset Paths in a SCSS Partial

I have the following setup:
app/assets/stylesheets/application.css.scss
/*
*= require_self
*= require fancybox
*/
/* COLORS.. */
/* MIXINS... */
/* FONT STACKS... */
/* IMPORTS */
#import "reset";
#import "supergrid";
#import "rails";
#import "app";
#import "forms";
#import "layout";
In my various partials I'm having a real problem with the asset paths. When inside application.css.scss or anything loaded by the manifest, I can use:
.example { background-image: image-path("background.png"); }
However, when I'm using a partial, such as my _layout.css.scss partial, when I try the same thing the background-image property is simply omitted from the compiled file. It seems the SCSS asset helpers are not available inside partials?
Has anyone gotten this to work, am I missing something obvious? Or is it simply impossible to use asset helpers in partials? If so this is a major, MAJOR problem, as my entire app structure depends on SCSS variables and mixins which are shared among the partials.
I know that variables and mixins are not shared across the sprockets manifest, so if partials cannot access the asset helpers then I'm looking at having to concatenate everything into a single scss file, which pretty much defeats the purpose of both Sass and Sprockets.
Any help would be very much appreciated!
Strange, it should work.. Just few ideas:
Are you using up-to-date gems sass-rails and sprockets?
Try to rename .css.scss to .scss
Try to replace image-path('background.png') with asset-url('background.png', image) or image-url('background.png')
Try to remove require_self from application.css.scss
Try to remove all directives from application.css.scss and import those files with #import

Resources