How do I use reference images in Sass when using Rails 3.1?

Ruby on-RailsCssRuby on-Rails-3SassSprockets

Ruby on-Rails Problem Overview


I have a Rails 3.1 project with the asset pipeline working great. The problem is that I need to reference images in my Sass, but Rails calculates image URLs. (This is particularly important in production, where Rails appends the Git hash of the image to its filename to bust caches.)

For example, in app/assets/stylesheets/todos.css.scss:

.button.checkable { background-image: url(/assets/tick.png); }

When I deploy (or run rake assets:precompile), the file app/assets/images/tick.png is moved to public/assets/tick-48fe85c0a.png or something similar. This breaks the CSS. This post makes two suggestions:

  1. don't use the asset pipeline for images -- instead put them in public/images/ and reference them directly
  2. use ERB for your CSS and let Rails work out the image URL.

Number 1 is certainly a possibility, though it means I don't get cache-busting on my images. Number 2 is out because I'm using Sass, not ERB to process the files.

Ruby on-Rails Solutions


Solution 1 - Ruby on-Rails

The following should do the trick:

.button.checkable { background-image: url(image_path('tick.png')); }

Rails in fact provides a bunch of helpers to reference the assets:

image-url('asset_name')
audio-path('asset_name')

In general

[asset_type]-url('asset_name') #Becomes url('assets/asset_name')
[asset_type]-path('asset_name') #Becomes 'assets/asset_name'

asset_type may be one of the following: image, font, video, audio, javascript, stylesheet

Solution 2 - Ruby on-Rails

sass-rails gem defines Sass functions that can be used from Sass, without ERB processing. https://github.com/rails/sass-rails

Solution 3 - Ruby on-Rails

For those who are in favor for faster load times for users, may I suggest following Steve Souders tip for loading images in CSS in base64.

asset-data-url('path')

https://github.com/rails/sass-rails#asset-helpers

Solution 4 - Ruby on-Rails

A variant of option 2 will work. If you have something like this:

app/assets/stylesheets/pancakes_house.css.less.erb

And you require it into your application.css file. Then pancakes_house goes through ERB first and that output goes through the LESS processor and whatever comes out of that goes into your CSS. Putting ERB inside your SCSS might feel a little odd but, hey, it'll work and get the job done without too much weirdness.

So you should be able to get at the necessary methods to produce your cache-busting image paths through your ERB.

I only tried this with a Less file but it should work with .css.scss.erb as well.


As an aside, you can also add your own functions to SASS:

> Methods in this module are accessible from the SassScript context. For example, you can write
> > $color = hsl(120deg, 100%, 50%) > > and it will call Sass::Script::Functions#hsl.

There are even some instructions on writing your own functions a little further down in the manual. However, I'm not sure how to get Sprockets to load your Sass::Script::Functions patches so I can't call this a practical solution; someone with stronger Sprocket Fu than me might be able to make this approach work though and I'd call this more elegant than ERBified SCSS.

Solution 5 - Ruby on-Rails

You can use Number 2 easily, just add .erb extension to your .scss file:

app/assets/stylesheets/todos.css.scss.erb

and use asset_path method to get path to image with hash:

.button.checkable { background-image: url('<%= asset_path 'tick.png' %>'); }

this file will be processed by erb and then by sass.

Solution 6 - Ruby on-Rails

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") returns url(/assets/rails.png) image-path("rails.png") returns "/assets/rails.png"

The more generic form can also be used:

asset-url("rails.png") returns url(/assets/rails.png) asset-path("rails.png") returns "/assets/rails.png"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJames A. RosenView Question on Stackoverflow
Solution 1 - Ruby on-RailsTopoView Answer on Stackoverflow
Solution 2 - Ruby on-RailsKliment MamykinView Answer on Stackoverflow
Solution 3 - Ruby on-RailsAlex GrandeView Answer on Stackoverflow
Solution 4 - Ruby on-Railsmu is too shortView Answer on Stackoverflow
Solution 5 - Ruby on-RailsLev LukomskyView Answer on Stackoverflow
Solution 6 - Ruby on-Railsoroyo segunView Answer on Stackoverflow