Different CSS files for different Layouts how to precompile? - ruby-on-rails

I want different CSS files for different Layouts.
For example:
app/layouts/application.html.erb would have application.css
<%= stylesheet_link_tag 'application' %>
and app/layouts/admin.html.erb will have admin.css:
<%= stylesheet_link_tag 'admin' %>
Problem is that the admin.css is not precompiled when I run:
RAILS_ENV=production bundle exec rake assets:precompile
What can I do that the admin.css is also precompiled?
I'm using Rails 4.2
EDIT
admin.css file
/*
//= require bootstrap.min
//= require filechooser
//= require bootstrap-switch.min
//= require jquery.datetimepicker
//= require fancybox2_1_5/jquery.fancybox
//= require blubb
*= require_self
But onlye the code of the blubb.css file is added in admin.css ....

In initializers/assets.rb :
Rails.application.config.assets.precompile += %w(admin.css)

Related

Precompile assets not loading properly

My application has a lot of 3rd party js/css files. We sped up the deploy by compiling these files into external-[hash].js and external-[hash].css (So Rails don't have to compile these files on every single deploy)
And loaded them like this in application.html.erb
<%= stylesheet_link_tag "external", :media => "all" %>
<%= javascript_include_tag "external" %>
These two files are under /public/assets/. This was working fine when we are on Rails 4. We are currently trying to upgrade to Rails 5, and these two files are not loading properly.
I changed the tags into below and in the chrome console, these files appear to have been loaded properly.
<%= stylesheet_link_tag "/assets/external-[hash]", :media => "all" %>
<%= javascript_include_tag "/assets/external-[hash]" %>
However, when I add in the application style/js tags below the external tags
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
I keep getting the error
Error: "img" failed to #extend ".img-responsive".
The selector ".img-responsive" was not found.
Use "#extend .img-responsive !optional" if the extend should be able to fail.
Looking into the external-[hash].css, I am able to see the .img-responsive selector defined. So, it seems like Rails 5 does not properly load these two files?
I'm currently using Rails 5.1.7, Ruby 2.4.2
I also tried adding config.public_file_server.enabled = true to environment files.
Here are how I've setup the external files.
I have an external.js, and external.scss, these files live under app/assets.
Inside application.js/css, I added stub external to both, so when the rails application deploys, it ignored the external files. I would run RAILS_ENV=external_assets rails assets:precompile and commit those files to git, expecting them to be loaded first.
Example external.js
//= require jquery
//= require jquery.turbolinks
//= require jquery_ujs
//= require jquery.readyselector
//= require bootstrap
//= require bootstrap-datepicker
//= require moment
//= require d3
//= require c3
//= require jsgrid.min
//= require bootstrap-datetimepicker
external.css
/*
*= require_self
*= require bootstrap-datepicker
*= require bootstrap-datetimepicker
*= require rails_bootstrap_forms
*= require c3
*= require jsgrid.min
*= require jsgrid-theme.min
*/
#import "font-awesome-sprockets";
#import "font-awesome";
#import 'bootstrap-sprockets';
#import 'bootstrap';
#import 'bootstrap-datetimepicker';
Please let me know if I can provide any other information.
Try some below commands
RAILS_ENV=production rails assets:clean
RAILS_ENV=production rails assets:clobber
And change in production
config.assets.compile = true
Then again run
RAILS_ENV=production rails assets:precompile

Flexslider' CSS is not loaded on my Rails Application

I am using the Flexslider 2 Rails Gem from https://github.com/constantm/Flexslider-2-Rails-Gem.
As informed in documentation, I called the JS and CSS, but only the CSS is not loaded (yes, JS works).
ruby -v: ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-darwin11.0]
rails -v: Rails 4.2.1
flexslider version: flexslider 2.2.0
My app/assets/stylesheets/application.css
*= require pineapple
*= require font-awesome
*= require dropzone/basic
*= require application/style
*= require fancybox
*= require flexslider.css
PS.: I tried require flexslider (without extension) too.
My app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require jquery.slimscroll.min
//= require pineapple
//= require tinymce
//= require dropzone
//= require jquery-ui/sortable
//= require jquery-ui/effect-highlight
//= require jquery-ui/tooltip
//= require jquery.mjs.nestedSortable
//= require general
//= require maskedinput
//= require fancybox
//= require jquery.flexslider
My HTML (I stripped others li tags here, but is the same)
<div id="carousel0" class="flexslider carousel">
<ul class="slides">
<li>
<%=link_to '/page/dynamic' do %>
<%=image_tag image_path('show-case-1.jpg'), alt: 'Show Case', title: 'Show Case', class: 'img-responsive' %>
<%end%>
</li>
</ul>
</div>
My custom .JS
$('#carousel0').flexslider({
animation: 'slide',
itemWidth: 300,
itemMargin: 100,
minItems: 2,
maxItems: 4,
pauseOnHover: true,
slideshowSpeed: 8000
});
There are no console errors.
Thanks for your help.
You are only including the library and providing the markup. But you don't "Hook up the slider". See step 3 https://www.woothemes.com/flexslider/
Have you tried:
*= require flexslider.sass
Shot in the dark after looking through the gem you're using
[SOLVED]
My app has some "specific pages". The app has multiple sites independent each other.
In my app/assets/stylesheets folder and app/assets/javascript folder I have 1 more CSS and JS beyond the application.(JS|CSS)
There are sitetype.css AND sitetype.js.
I called require flexslider.css in sitetype.css AND //= require jquery.flexslider in sitetype.js and it works.
Thanks all for the help.

Why does the Rails asset pipeline not work surprise-free with subdirectories?

I'm using Rails 3.2, and am somewhat confused about the handling of subdirectories and relative paths of the asset pipeline.
My situation
I'm trying to include four code files in (javascripts/edit), one of them being in the subdirectory javascripts/edit/ckeditor, in a manifest file, (javascripts/edit/all.js). I'm not including these in the application.js because I want to include these scripts only on certain pages.
Doing //= require ckeditor/ckeditor doesn't work. Doing //= require mycode (to require javascripts/edit/mycode.js), too, doesn't work, apparently because mycode.js is in the "edit" subdirectory of the javascripts "root" folder. To make it work, I had to put this:
//= require ./ckeditor/ckeditor
//= require ./json2
//= require ./cssjson
//= require ./mycode
inside of my manifest all.js. Note that this:
//= require edit/ckeditor/ckeditor
//= require edit/json2
//= require edit/cssjson
//= require edit/mycode
works exactly the same, even though all.js itself is already in the edit subdirectory.
So my question is, why does this work this way? I would expect to be able to put manifest files in subdirectories and just include files that are in that same subdirectory (e.g. //= require json2), but apparently, all //= require directives in any file below app/assets/javascripts always are relative to that "root" folder, not the subdirectory that the manifest files are in.
So my question is, why does this work this way?
Because when Rails compiles the assets, it's compiling from a central point, not your subdirectory. The manifest system works based on the assets' root path (the documentation says The first feature of the pipeline is to concatenate assets), consequently your assets will be compiled from the application.js file
You have to remember when Rails runs, it's not loading the assets dynamically. It's designed to load application.css / application.js all the time, and it's then up to the developer to delegate assets which they wish to load on specific pages
The way we do this is to include all the "constant" files in our application.js file, and then load controller-specific assets in the layout. This allows us to only call things like JQuery all the time, whilst we may call specific JQuery plugins for certain controllers:
Including The Right Assets In The Right Places
This is what we do:
#app/views/layouts/application.html.erb
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= stylesheet_link_tag controller_name, media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag controller_name, "data-turbolinks-track" => true %>
#app/assets/javascripts/application.js
//= require jquery
//= require jquery_ujs
//= require jquery.ui.draggable
//= require_tree ./jquery
//= require_tree ./extra
//= require turbolinks
#app/assets/javascripts/users.js.erb
//= require ** anything you want **
This allows you to have a lot more control over which assets you're loading

Asset pipeline: use javascript files for only one controller

In Ruby on Rails v4, I want a js file (or set of js files) to be only loaded for a particular controller.
What is the standard way to do this?
In application.js there is the //= require tree . line. I'm assuming this would need to be removed so I'm not always loading every file. But then what? Will a file named mycontroller.js always be loaded when Mycontroller is used?
The asset pipeline can be very powerful if you do it right:
Manifests
The purpose of //= require tree . is to create a "manifest" file which Rails will use to render the files you call. If you don't "precompile" your assets, this means that each time your browser loads your app, it will look for the files contained in your manifest & load them
This means that you can define what you call in your manifest & what you don't. We prefer to call any gem-based assets in the manifest, but also designate specific folders, like this:
//
//= require jquery
//= require jquery_ujs
//= require jquery.ui.draggable
//= require_tree ./jquery
//= require_tree ./extra
//= require turbolinks
We use this setup to call all JQuery plugins & any extra JS, as well as the gem-specific files
Precompiling
If you pre-compile your assets, it basically builds different files which are loaded consistently when you load the browser. If you're using Heroku or a CDN, you may wish to precompile your assets, as to reduce latency & dependency
Application Design
To answer your question, you can certainly load controller-specific JS. We do it like this:
#app/views/layouts/application.html.erb
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= stylesheet_link_tag controller_name, media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag controller_name, "data-turbolinks-track" => true %>
You can then ensure your JS files are split up by using what Phoet described:
#config/environments/production.rb
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
config.assets.precompile += %w(mycontroller.js)
Then for application.js, you can only call the files you want to persist throughout the app:
#app/assets/javascripts/application.js
//
//= require jquery
//= require jquery_ujs
//= require jquery.ui.draggable
//= require_tree ./jquery
//= require_tree ./extra
//= require turbolinks
It works like this:
You define additional files that should be precompiled:
# Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
config.assets.precompile += %w(mycontroller.js)
Then in your layout you implement some logic to include this file:
= javascript_include_tag "#{controller_name}.js" if controller_name == 'mycontroller'

config.assets.precompile not working

I have a bookmarklet, which needs separate js and css files - i.e. I don't want them compiled as usual into one file.
These are the files that I want to separate from the usual js and css files:
assets/javascripts/bookmarklet/tagger.js
assets/javascripts/bookmarklet/js/bookmarklet.js
assets/stylesheets/bookmarklet/bookmarklet-frame.css
In application.js and application.css I changed //= require_three . to //= require_directory .
And I added:
config.assets.precompile += [ 'bookmarklet/js/bookmarklet.js', 'bookmarklet/tagger.js', 'bookmarklet/bookmarklet-frame.css' ]
to my production.rb and staging.rb.
An application.js and application.css is generated, however, my three separate files are not. Any idea why this is not working?
Make sure you have require_tree instead of require_directory, require_tree adds recursively but require_directory does not. Refer asset pipeline
application.js
//= require jquery
//= require jquery_ujs
//= require_tree .
application.css
/* ...
*= require_self
*= require_tree .
*/
application.html.erb should have these lines
<%= javascript_include_tag "application" %>
<%= stylesheet_link_tag "application" %>
Now when you precompile the assets with command RAILS_ENV=production bundle exec rake assets:precompile in your production you will have(all the js files compiled into one, css into one)
application.html.erb
<script src="/assets/application-908e25f4bf641868d8683022a5b62f54.js"></script>
<link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" media="screen" rel="stylesheet" />
This is unnecessary as by default application.js, application.css are precompiled.
config.assets.precompile += [ 'bookmarklet/js/bookmarklet.js', 'bookmarklet/tagger.js', 'bookmarklet/bookmarklet-frame.css' ]
Sometimes you may use admin.js for a layout admin.html.erb only then you need to add a line like this in production.rb
Had to move
config.assets.precompile += [ 'bookmarklet/js/bookmarklet.js', 'bookmarklet/tagger.js', 'bookmarklet/bookmarklet-frame.css' ]
to application.rb.
Another solution to consider where moving to application.rb may not be necessary. Instead, add 'production' to :assets in your config/application.rb. 'production' is by default not included in the list.
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require(*Rails.groups(:assets => %w(development test production)))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end

Resources