What's the benefit of Rails asset pipeline for images - ruby-on-rails

Asset Pipeline is made up of 3 processes - precompile, concatenation, and minification.
I understand that JavaScript and CSS can benefit from it. However, I can't think of any benefits for images.
Can you explain it, please?
Thanks.
Sam

Assuming you use Rails helpers for images (e.g. image_tag), versioning/fingerprining is the primary benefit.
The fingerprinting helps to bust cache (both from a CDN and browser perspective).
See this rails guide section.

One benefit to passing images through the Rails asset pipeline is to take advantage of asset fingerprinting, which lets you set far-future caching headers and busts the cache when the asset changes.
When a filename is unique and based on its content, HTTP headers can be set to encourage caches everywhere (whether at CDNs, at ISPs, in networking equipment, or in web browsers) to keep their own copy of the content. When the content is updated, the fingerprint will change. This will cause the remote clients to request a new copy of the content. This is generally known as cache busting. ( from the Ruby on Rails Guides: Asset Pipeline)

When rendering SVG files in your Ruby CSS files
Example
.benefits__icon::after {
content: "";
background: url("learn-investment-investxd.svg") no-repeat;
background-size: 52px;
}
with an assets.rb file as such
Rails.application.config.assets.precompile += %w( application.css dashboard.css dashboard.js)` with no other configuration.
The example above, the background url would restore to http://localhost:3001/learn-investment-investxd.png even if I place the image file learn-investment-investxd.png in my assets/images folder.
My workaround
I added assets to the url.
.benefits__icon::after {
content: "";
background: url("assets/learn-investment-investxd.svg") no-repeat;
background-size: 52px;
}
This works.
It can be improved

Related

Don't show background images on Heroku. But local is working

My tag:
= link_to '', root_path, class: 'items__footage'
My selector:
.items__footage {
display: inline-block;
content: '';
width: 300px;
min-height: 300px;
background: url('/assets/footage_still.png') no-repeat;
background-size: auto 100%;
}
The path of my image is assets/images/footage_still.png. If I indicate this path, my image does not work locally.
I have done rake assets:precompile. But it did not help.
if you can use ruby code in your css file then use items_footage's background like this.
background: url("<%= asset_path('footage_still.png') %>");
To use ruby code inside css file make that file as filename.css.erb
From the documentation
In the production environment Sprockets uses the fingerprinting scheme
outlined above. By default Rails assumes assets have been precompiled
and will be served as static assets by your web server.
During the precompilation phase an SHA256 is generated from the
contents of the compiled files, and inserted into the filenames as
they are written to disk. These fingerprinted names are used by the
Rails helpers in place of the manifest name.
So, in production all your assets will be precompiled and will be served from public/assets. Also the file will be renamed with a fingerprint. So actually In production your file name will look something like
footage_still-908e25f4bf641868d8683022a5b62f54.png
The fingerprint will changes every time the file content changes and is useful for caching the static assets, generally called cache busting.
So when you hard code the image url /assets/footage_still.png, it will break in production. To handle the situation, rails provides something called asset url helpers.
To make it work, you have to rename your .css file to .scss if not and change.
background: url('/assets/footage_still.png') no-repeat;
to
background: image_url('footage_still.png') no-repeat;
Hope this helps.
You can use image_url('footage_still.png') and let rails find the path of the image

Rails 3.1 asset pipeline css styles in 404 static page

I am building a static public/404.html page. Before Rails 3.1 I can reference it with the public/style.css. But now with asset pipeline I am not sure what to link to. I heard that the styles will be compiled into asset/application.css. But on production it will come with a timestamp.
What is the best approach to style the static 404.html with the normal styles I work with?
You can precompile static error pages with asset pipeline too!
Inside application.rb:
config.assets.paths << "#{Rails.root}/app/assets/html"
config.assets.precompile += %w(404.html 500.html)
Create in assets/html/ files 404.html.erb and 500.html.erb and use many helpers there, like stylesheet_link_tag, javascript_include_tag, image_tag.
Then setup your server to use precompiled public/assets/404.html and public/assets/500.html
All credits for this clever solution goes to http://neovintage.blogspot.cz/2012/02/precompile-static-html-pages-with-rails.html
It's true that the assets in 3.1 come with a digest in production, but you can still use the regular file, meaning that you can link to /assets/application.css and you won't have any problems (try it! :)).

Rails Asset Pipeline: Precompile Assets outside of manifest?

I have certain page-specific js and css files that I either:
Don't want running on development (ie tracking code)
Don't want running on every page
or both.
In Rails 3.0.x I would simply call them from the view where they are needed like so:
- if some_condition
= javascript_include_tag 'page_specific'
Now, using the asset pipeline, it looks like I must include these in the manifest (and therefore in every page for the application) or else they won't be precompiled. As I'm using Heroku for deployment allowing lazy compilation is not an option.
How can I manually precompile every file from the assets directory without having to include them all in the manifest? Is this possible?
Just don't put the page specific asset in the manifest and include them when you need it like you did in rails 3.0.x, the precompiler will compile those page specific as separate files.
Personally I just check for a certain element I know is in the dom in that page. If the element isn't found the rest of the code isn't executed.
$(function(){
if( $("#page_specific_element").length !== 1 ) return;
//page specific functions
});

Asset Subdirectories in Rails 3.1

I have a Rails 3.1 app with an image:
app/assets/images/icons/button.png
It seems like the image should be served at this URL:
assets/icons/button.png
but if I go to this URL I get a 404. To fix this I created an initializer and added my images/icons subdirectory to the asset path:
Rails.application.assets.append_path "app/assets/images/icons"
However, this does not seem like it can possibly be the recommended way to accomplish this. I'm aware of the require and require_tree directives for JavaScript and CSS assets, is there an equivalent for image assets? How are other people doing this?
EDIT: As of Rails 3.2.rc1 this is now fixed! asset_path now generates proper paths when deploying to sub-uri!
For images it just works. Rails packages everything in images/ tree. I personally use them like this (actual code):
CSS:
a#icon-followers{
background: url(<%= asset_data_uri "icons/followers.png" %>) center center no-repeat;
}
(asset_data_uri actually makes the images inline in the CSS file using base64, but that's irrelevant in this case)
No custom configuration required. After precompiling, images from app/assets/icons/ end up in public/assets/icons/.
You can open public/assets/manifest.yml to see how Rails translates the paths to actual files.

Rails 3: How to prevent image caching when the image is specified in the CSS file?

Consider the following CSS:
.my_class {
background-image: url(/images/sprites.png);
}
Sometimes I change sprites.png by adding new sprites to it, so I don't want the browser to cache it.
One idea I thought of is to add style="background-image: url(/images/sprites.png?<random_number_here>)" to all elements with class my_class, and delete the CSS code above.
But, I don't like this solution because of maintainability issues (if for example the file name changes, I have to change it in many places, rather than a single CSS).
What other solutions exist to this problem ?
One way around this is to add a version string to your style directory.
<link rel="stylesheet" href="/css.1000/styles.css" type="text/css" />
Ensure that your css uses URLs relative to that directory. (In this example, the image directory for css links is css.1000/image)
.my_class {
background-image: url(images/sprites.png);
}
Then, use mod_rewrite to add a rewrite rule to the .htaccess file in your site's root folder, this will make any numerical path /css.1000/styles.css point to /css/styles.css on the server:
RewriteEngine On
RewriteRule css[\.][0-9]+/(.*)$ css/$1 [L]
Any time you change your site's assets, you change the version number of the folder in your stylesheet link.
I would suggest one of these two techniques:
Use Javascript to perform the cache update technique.
$('.my_class').ready(function() {
$(this).css('background-image',
$(this).css('background-image') + "?" + Math.random());
}
Use specific server content-control for your given page. This is from this StackExchange answer for nginx (similar techniques exist in apache):
server {
...
location = /images/sprites.png {
expires 1d;
}
...
}
These will both work to help mitigate your issue. Good luck!
Use rails asset pipeline (i.e. rails > 3.1), and it automatically does this for you via the fingerprinting mechanism:
http://guides.rubyonrails.org/asset_pipeline.html#what-is-fingerprinting-and-why-should-i-care-questionmark
Rename your mycss.css to mycss.css.erb and specify the images as:
.my_class { background-image: url(<%= asset_path 'image.png' %>) }
Rails will take care of everything else (you need to enable asset precompilation as well).

Resources