Asset pipelining for individual view with fingerprinting - ruby-on-rails-4

I'm using rails 4.0 with ruby 2.0.
And i've 100's of js and css files. I dont want them to load on all pages.
So i removed require_tree in application.js and application.css
I include the required css and js using
<% javascript_include_tag "js_file" %>
<% stylesheet_include_tag "css_file" %>
My questions are
1. Do i need to precompile assets?
2. Will they be formed into a single file and sent on client side?
3. What is and how can turbo_link gem help me here?
4. Should i use controller based assets and use their appropriate cs and js file for inclusion?

1. Do I need to precompile assets?
No, but it entirely depends on your production environment. Services such as Heroku require precompiled assets
2. Will they be formed into a single file and sent on client side?
The assets which are required in the application.css will be merged into that file. However, if you have controller-specific css/js, and call them from your layout accordingly, they should be compiled into their respective files
3. What is and how can turbo_link gem help me here?
Turbolinks is a gem designed to help boost page load times, by cutting down the number of times the elements have to be loaded. Basically, if you're using the same controller, turbolinks will just replace the part of your page with an Ajax request
So nope, Turbolinks won't help you with compilation / organization of your assets :)
4. Should I use controller based assets and use their appropriate cs and js file for inclusion?
It depends on your application. The first question I would have is.... why do you have 100's of CSS & JS files? After you find the answer to this, you can then work on making the system work to the most efficient requirements

Related

Referencing asset in javascript

The Ember CLI guide describes how assets can be referenced in the templates and the CSS - but what is the proper way of referencing an asset (say an image) from my javascript code?
Specifically I am concerned about the asset path getting fingerprinted correctly when building assets for production. It seems like ember-cli is using broccoli-asset-rev for this, but according to its documentation, only <script> tags in the HTML and url() in CSS will be fingerprinted. Is there any way (probably through another broccoli plugin) to get asset paths in the .js files fingerprinted, too?
I placed an image called car.jpeg under public/assets/images and then was able to reference it in my application.js route file as assets/images/car.jpeg
Works great
UPDATE
One picture is worth a thousand words... :)
I found the issue. This works out of the box as expected - it turned out that my asset (image) was not in the right location, so occurrences of it's path in the JS files never got replaced with the fingerprinted version.

font-awesome-rails gem not loading pre compiled fonts

I am using the font-awesome-rails gem within my app and all is working in development, however when deployed in production the fonts do not show. I have tried browsing /assets/fontawesome-webfont.eot on the production site and get a 404 not found error. Looking on the server I can see the fonts are pre-compiled with a different name - e.g. /assets/fontawesome-webfont-e732c0065276ad722bded99096afaa19.eot
I have the
*= require font-awesome
line in my application.css file and when looking at the compiled css file can see it included:
Font Awesome 4.2.0 by #davegandy - http://fontawesome.io - #fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/#font-face{font-family:'FontAwesome';src:url("/assets/fontawesome-webfont.eot?v=4.2.0");src:url("/assets/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),url("/assets/fontawesome-webfont.woff?v=4.2.0") format("woff"),url("/assets/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),url("/assets/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");
The problem seems to be the difference in filenames between the file in the assets folder and the css call
I don't know how to call these font files within the CSS as the file name changes every time they are pre-compiled.
What is happening is Rails is giving your assets (in this case, the font file) a unique name by adding an MD5 hash to the filename. When you update an asset, this will ensure the users' browsers do not cache the old file.
As you've observed, the CSS file is not using the unique name. This is because Rails doesn't know to update that reference.
There are several approaches you can use; I'll cover two here.
Use an Asset Helper
In order to do this, you will need to rename your static CSS file to a ERB file (i.e., rename stylesheet.css to stylesheet.css.erb). Then in the font reference:
#font-face{
font-family:'FontAwesome';
src:url("/assets/fontawesome-webfont.eot?v=4.2.0");
src:url("/assets/fontawesome-webfont.eot?#iefix&v=4.2.0") format("embedded-opentype"),
url("/assets/fontawesome-webfont.woff?v=4.2.0") format("woff"),
url("/assets/fontawesome-webfont.ttf?v=4.2.0") format("truetype"),
url("/assets/fontawesome-webfont.svg?v=4.2.0#fontawesomeregular") format("svg");
You will use the asset_path helper:
url(<%= asset_path 'fontawesome-webfont.woff' %>)
url(<%= asset_path 'fontawesome-webfont.ttf' %>)
url(<%= asset_path 'fontawesome-webfont.svg' %>)
During runtime, rails will handle the unique names and insert the correct value in the CSS.
Use a CDN
For some common assets, like some fonts, jQuery, etc, using a CDN might make sense. With your external reference, Rails will not rename the file and your users may gain the benefits of caching.
When I search "fontawesome cdn", I get a link to a CDN that hosts both the CSS and the font files.

sprockets - precompiling a standalone asset

I am trying to make sprokets compile a single standalone js asset, so it will uglify and minify it and be part of the entire rails projects.
I need that this js to have a non-digest name, so it's will not change (i.e. embedded in other websites, etc)
I can't seem to force rails (4) /sprockets to do my bidding.
What I tried:
Adding the asset (script.js) in a misc folder unders assets/javascripts and not load it in the sprockets javascript manifest. While this keeps it in the project, it doesn't get uglified and minified, and doesn't get automatically loaded via asset-sync.
Tried adding another manifest called scripts-manifest.js to //= require script.js asset, to add its path in the precompile path in application.rb, but the problem is that rails 4 adds digest to all assets no matter what (doesn't work like that in rails 3)
Tried using https://github.com/alexspeller/non-stupid-digest-assets to add a non digest version of the asset. I may have done it incorrectly, as it doesn't work or do anything..
I add the initializer NonStupidDigestAssets.whitelist = ["script.js"] and tried putting it in app/assets/javascripts/misc and in public/ but it still won't work/
I have read that this gem should help in most cases, and I am sure I am doing something wrong with either path definition or no including it somewhere
One way to do this is to add an initializer that generates the compiled versions directly.
Add your js file to a subfolder in /app/assets/javascripts. Don't include this in application.js so it isn't added to the compiled assets.
Create an initializer in /config/initializers that uses uglify directly
output_file = "#{Rails.root}/public/public_script.js"
input_file = "#{Rails.root}/app/assets/javascripts/non_digest/public_script.js"
uglified = Uglifier.compile(File.read(input_file))
File.open(output_file, 'w') {|f| f.write(uglified) }
Include the public js file (in this example: /public/public_script.js) in your application layout
This way you have direct access to make custom changes to how uglify handles your js and the location of the file never changes for your external services accessing them.
I did all this locally and tested that it worked using the beta version of Rails 4.2
Just wanted to add my own solution based off Ken's answer.
I created non_digest.rb in config/initializers:
Dir["#{Rails.root}/app/assets/javascripts/non_digest/*"].each do |asset|
asset_name = File.basename(asset)
asset_output = "#{Rails.root}/public/external/#{asset_name}"
asset_uglified = Uglifier.compile(File.read(asset))
File.open(asset_output, 'w') {|a| a.write(asset_uglified) }
end
Don't forget to stub the file in javascripts/application.js. as we probably don't want it compiled with the rest of our JS and we can continue to use //= require_tree .:
//= stub non_digest/external_bookmarklet
the way you would do this with rails 4 is the following:
add it to the precompile list config.assets.precompile += %w(your_file_name.js)
make sure it's not referenced in application.js (directly or via require_tree)
symlink the digested file on deployment
read the manifest.yml to get the actual filename
ln -s digested-filename.js actual-filename.js
since rails 4, generation of non-digested assets has been removed (for good reasons) and this is a simple and straight forward way to implement the desired behavior.

How could I not include all the css and js files in every page in rails 4.0?

I'm a newbie. Here's my problem. I just found that all css and js files generated by rails under app/assets are included in every page. I was considering how I could separate them into local ones(just for this page), and global ones(for all pages).
For example, I would like to put jquery.js in all my pages. But for 3DHelper.js, I hope it only appear in specific pages.
Are there any good ways to do this?
Assets pipeline gives you a good improvements in performance when you avoid using separate css/js files in your APP. And it is strongly recommended to follow this way!
If you would like some js file is executed only on some pages you can do the following:
add controller/action names to data or class attribute to body (in layout)
<body data-controller="<%= controller.controller_name %>" data-action="<%= controller.action_name %>">
add if condition to your js file which should be executed only on specific page. Something like this
if (($('body').data('controller') == 'YourSpecificController') && ($('body').data('action') == 'YourSpecificAction'))

Mercury Editor with rails4

i'm wondering how to use mercury gem with rails4.
i tried to follow guide http://asciicasts.com/episodes/296-mercury-editor
if i load page within editor ( /editor/pages/1) i see error in javascript console:
Uncaught TypeError: Cannot read property 'konqueror' of undefined
and mercury-region isn't visible at page at all
Gemfile:
gem 'mercury-rails', github: 'jejacks0n/mercury'
app/views/pages/show.html.erb:
<div id="page_body" class="mercury-region" data-type="editable">
<%= raw(#page.body) %>
</div>
after some delay i get javascript alert with message:
Mercury.PageEditor failed to load: Region type is malformed, no data-type provided, or "Full" is unknown for the "page_body" region.
Please try refreshing.
mercury is utilising jquery.browser this method is deprecated in the most recent update.
If you include gem 'jquery-migrate-rails' in your gemfile that you should work favourably until mercury updates it's code to the latest jquery or at least 1.9
You'll need to add
//= require jquery-migrate-min
to your application.js after jquery is loaded.
I just had the same issue. I describe it better in my own question here, but basically the issue comes from a deprecated jquery method calling 'konqueror'. I don't think it had anything to do with your app being in rails 4 btw. I'm in gem 'rails', '3.2.13'
I'd up-vote the question but apparently I need more reputation. hint, hint :)
I had a similar issue with this because of turbolinks. I just disabled its JS in applications.js:
//= require turbolinks
~to:
// require turbolinks
-until I figure out how to get them to play nicely together. At least for the Mercury pages, have to poke them somehow.
I have some issues too, it does seem to be an issue with Turbolinks. I was able to get by it by removing the line:
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
from my application.html.erb file, not sure if this will cause issues down the road