sprockets - multiple entry points? - ruby-on-rails

Sprockets official documentation clearly says that:
Sprockets takes any number of source files and preprocesses them
line-by-line in order to build a `single` concatenation.
I'm a big fan of sprockets in Rails but here's the problem - my application has to support multiple layouts(desktop browsers) and mobile clients(iphone, ipad, android phones etc).
Both of this layouts require their own HTML reset CSS rules. Concatenated rules of desktop&mobile reset files would make a conflict because they override low level CSS directives.
How can I fix that?

You can get multiple top-level CSS files by making a Sprocket file for each. For example, say you want desktop.css to be comprised of reset.css, common.css, and ie.css and mobile.css to be comprised of common.css and ios.css. You would have the following files:
app/assets/stylesheets/desktop.css
app/assets/stylesheets/mobile.css
app/assets/stylesheets/reset.css
app/assets/stylesheets/common.css
app/assets/stylesheets/ie.css
app/assets/stylesheets/ios.css
In desktop.css, you would have the following:
/*
*= require reset.css
*= require common.css
*= require ie.css
*/
In mobile.css, you would have the following:
/*
*= require common.css
*= require ios.css
*/
Then, in app/views/layouts/desktop.html.erb, you would do
<%= stylesheet_link_tag :desktop, :debug => Rails.env.development? %>
and similarly for mobile.html.erb.
Lastly, you'll need to set the precompiled asset list in config/environments/production.rb:
config.assets.precompile = %w( desktop.css mobile.css )

I'm not really sure if sprockets supports this but I know that if you use the Jammit gem. You can setup different packages each with it's own cocktail of your JS or css files. e.g. have a :workspace package for desktop and and :mobile package for mobiles.
It is all defined in a config yaml file and it will concat them in the order you list them, which can help get plugin dependencies correct etc.
javascripts:
workspace:
- public/javascripts/vendor/jquery.js
- public/javascripts/lib/*.js
- public/javascripts/views/**/*.js
- app/views/workspace/*.jst
mobile:
- public/javascripts/vendor/jquery.js
- public/javascripts/lib/mobile.js
stylesheets:
common:
- public/stylesheets/reset.css
- public/stylesheets/widgets/*.css
workspace:
- public/stylesheets/pages/workspace.css
mobile:
- public/stylesheets/pages/mobile.css
Jammit might be worth a look for your needs
Hope this helps.

I'm assuming you already have different layouts for each device or device group. If so, just include a different top-level css file in each, then have different require statements in those top-level files. If you're using Rails 3.1, there's no reason you have to keep the built-in line that includes all css files.

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 to make Rails not import every file from app/assets/stylesheets?

In app/assets/stylesheets, I have many sass files. In a requested page, every file in app/assets/stylesheets is imported (with a tag). How do I make it so that not every file from the directory is imported, but only the ones that I pick?
Note: I'm running Rails 4.1.2
You change your app/assets/stylesheets/application.css file.
Instead of *=require_tree .
Add:
*=require './file1'
*=require './file2'
...
You don't need to supply .css or .css.scss
Manifest
As alluded to by #Ruby Racer, you'll be looking to manipulate the manifest of your stylesheets in your application:
Sprockets uses manifest files to determine which assets to include and
serve. These manifest files contain directives - instructions that
tell Sprockets which files to require in order to build a single CSS
or JavaScript file.
The way to use this is at the top of any of your css files, typically your application.css file -
/app/assets/stylesheets/application.css
/* = require "file" */
By doing this, you'll be able to build your stylesheet assets as you require
--
SASS
If it's only the stylesheets you want to change, you need to remember something else -
If you changed the extension of your CSS to .css.scss, you'll be able to call the #import function of SASS to create a similar effect to the manifest functionality:
#app/assets/stylesheets/application.css.scss
#import "file"

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 :)

Is there something like stylesheet_url on Rails 3.1?

I want to use application.css on my email templates, but I can't find a way to make the stylesheet_link_tag helper to include the full url of the stylesheet so email clients can render properly.
By default, stylesheet_link_tag only adds the relative path, so, I want to know if there is a way to either tell stylesheet_link_tay to use the url, or a helper that returns the url to the stylesheet.
This is for Rails 3.1, by the way
Rails 3.1 uses asset pipeline. If you are using asset pipeline then you need to mention those assets in you application.css. For example in application.css
/*
* *application.css
*= require scaffold
*= require pagination
*= require_self
*= require_tree.
*/
In the above scaffold and pagination should be under rails_root/app/assets/stylesheets ditrectory. For more info check this out http://guides.rubyonrails.org/asset_pipeline.html
Or if asset pipeline is not your issue then check this railcast for HTML Email.
http://railscasts.com/episodes/312-sending-html-email?view=asciicast
You may consider that the <link rel=stylesheet> isn't supported by the mayor providers like Hotmail, Gmail and Yahoo: http://www.campaignmonitor.com/css/
The best option that you have is using <styles> tags in your body or header; or even uglier, using the inline styles, that is supported by most of the email clients today.
Google Mail, in particular, looks for STYLE anywhere in the email and (helpfully) deletes it. And don’t bother to use CSS LINK to a stylesheet. Google Mail, Hotmail, and other email software ignore, modify, or delete these external references to a stylesheet.
http://www.reachcustomersonline.com/2011/12/21/09.27.00/
you can specify the full path of your assets by using
config.action_controller.asset_host = "http://www.yourdomainFORassets.com"
in your environment config file
And you better be careful with the images URL inside CSS files, I have to move everything
to this way to use existing code, check http://guides.rubyonrails.org/asset_pipeline.html
specially with this part:
2.2.2 CSS and Sass
When using the asset pipeline, paths to assets must be re-written and sass-rails provides -url and -path helpers (hyphenated in Sass, underscored in Ruby) for the following asset classes: image, font, video, audio, JavaScript and stylesheet.
image-url("rails.png") becomes url(/assets/rails.png)
image-path("rails.png") becomes "/assets/rails.png".
The more generic form can also be used but the asset path and class must both be specified:
asset-url("rails.png", image) becomes url(/assets/rails.png)
asset-path("rails.png", image) becomes "/assets/rails.png"
http://guides.rubyonrails.org/asset_pipeline.html#in-production
Regards

Where to put Galleria (jQuery image gallery framework) in Rails 3.1 Asset Pipeline?

I'm a bit confused as to where to put a jQuery framework like Galleria in Rails 3.1's new Asset Pipeline?
I know it, technically, should go into /vendors/assets/javascripts but, it is my understanding that, the Galleria folder with the jQuery & themes wants to be in root (/galleria) of the live site in order to work correctly.
Also, while we're at it, where to put the following script so it will appear only on the page(s) with a gallery?
<script>
$('#gallery').galleria({
width:500,
height:500
});
</script>
Edit: Surprised there's no response!?! Maybe Galleria isn't that popular? These are the files I'm trying to load. They are bundled like this though I could easily move them:
vendor/
assets/
javascripts/
galleria-1.2.5.js
galleria-1.2.5.min.js
galleria/
themes/
classic/
classic-loader.gif
classic-map.png
galleria.classic.css
galleria.classic.js
galleria.classic.min.js
i thought Sprockets require_tree . would load everything in app/assets, lib/assets and vendor/assets?!?
I had the same problem, and it took a while to get working. Initially, it would work fine on development, but when we moved to production, Galleria silently failed, due to the asset filenames now having "fingerprints". This also seems to be an issue with jQuery UI themes, and many other such scripts.
Of course, you could just go back to the old way of doing things and throw everything in "public", but we would like the advantage of automatically merging all css/js files, and doing things the rails way.
This is how I got it working:
vendor/
assets/
images/
classic-loader.gif
classic-map.gif
javascripts/
galleria-1.2.5.js
galleria.classic.js
stylesheets
galleria.classic.css.scss
Rename your galleria.classic.css file to galleria.classic.css.scss. Then replace the image references, like so (I had two):
url("classic-loader.gif") becomes image-url("classic-loader.gif")
UPDATE: It looks like you don't need to do this in Rails 3.1.1. Just rename the file to .css.scss and rails will automatically preprocess the url() calls for you.
In your app/assets/javascripts/application.js file, make sure you have the lines
//= require galleria-1.2.5
//= require galleria.classic
//= require_tree .
In you app/assets/stylesheets/application.css file, make sure you have the lines
*= require galleria.classic
*= require_tree .
Finally, Galleria seems to have some fancy non-standard css loading built in. This is what was preventing Galleria from loading on our production website. Since we have already included the stylesheet, we want to disable this behavior. Simply open up galleria.classic.js (or your Galleria theme javascript file), and replace the line:
css: 'galleria.classic.css',
with:
css: false,
This will tell Galleria not to try loading the stylesheet.
One more thing - when trying to compile these assets, I ran into what is apparently a bug in Rails 3.1.0. When I ran rake assets:precompile, I got errors like:
$ bundle exec rake assets:precompile
rake aborted!
classic-loader.gif isn't precompiled
(in /vendor/assets/stylesheets/galleria.classic.css.scss)
Long story short, you need to set this line in config/environments/production.rb:
config.assets.compile = true
This shouldn't be necessary once 3.1.1 is released.
I like Arjen's suggestion, though I think vendor/assets/libs is more appropriate. Here's my setup:
In config/application.rb
config.assets.enabled = true
config.assets.paths << "#{Rails.root}/vendor/assets/libs"
In app/assets/javascripts/application.js
//= require galleria/galleria-1.2.6.min.js
To initialize:
Galleria.loadTheme('assets/galleria/themes/classic/galleria.classic.min.js');
$('#gallery').galleria();
Notice how the path passed to loadTheme() begins with 'assets'.
I like this setup because it keeps the galleria folder intact. Also, it concatenates galleria-1.2.6.min.js onto my main js file (one less http request).
I've also stumbled upon this problem. Dividing up an existing library so it fits into the current javascripts/stylesheets structure is a bit of a hassle. Therefor you can add an extra path to your application.rb file to load assets from, like this:
# Enable the asset pipeline
config.assets.enabled = true
config.assets.paths << "#{Rails.root}/app/assets/libs"
Create a 'libs' folder under app/assets, copy the galleria library to this folder and add this to your application layout file:
<%= javascript_include_tag 'galleria/galleria-1.2.4.min.js' %>
<%= javascript_include_tag 'galleria/themes/classic/galleria.classic.min.js' %>
You could also bundle up the galleria code by requiring the js files, but that's up to you.

Resources