1

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 ?

Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
  • Why not just expire the cache when there is a change? A client should query the server and see if the content is modified before displaying the local cache. – Devin M Aug 15 '11 at 00:15
  • @Devin: How could I expire the cache ? – Misha Moroshko Aug 15 '11 at 02:19
  • Rails should append a timestamp to assets automatically, See http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html under the heading "Customizing the asset path" – Devin M Aug 15 '11 at 02:29
  • @Devin M While it's true that rails provides a timestamp for css and image links, as far as I know this doesn't apply to css `background-image` links. – ghoppe Aug 15 '11 at 17:47

3 Answers3

1

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.

ghoppe
  • 21,452
  • 3
  • 30
  • 21
1

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!

Community
  • 1
  • 1
hayesgm
  • 8,678
  • 1
  • 38
  • 40
0

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

amit_saxena
  • 7,450
  • 5
  • 49
  • 64