64

I'm starting a new project in Rails, and it looks like the application.js manifest file is doing something funny with the javascripts that I reference - does it cache those files as part of the asset pipeline?

Here's what happened. I added a javascript file named jquery.autoresize.js to the vendor/assets/javascripts folder, and then referenced the file in the application.js manifest like this:

//= require jquery.autoresize.js 

Then I started up the rails server. But after navigating around in my app, I realized that I had accidentally added the wrong version of the jquery.autoresize.js file. So, I deleted that file and then added the correct version to the vendor/assets/javascripts folder. But, to my horror, when I reloaded the page, it is still loading the old javascript file.

I tried emptying my browser cache, then exiting and restarting the Rails server, but to no avail. I hacked a solution together by simply renaming my javascript file and referencing the new name, which worked fine. But there has got to be a better solution to this.

Does the new asset pipeline cache the files you reference somehow? If so, how can I clear that cache? Thanks for any help!

Aaron Gray
  • 11,283
  • 7
  • 55
  • 61
  • 3
    I cannot believe I wasted over an hour on this. What finally fixed it for me was resetting the **browser's cache!** Chrome > Clear Browsing Data > Cached Images & Files – wetjosh Apr 07 '19 at 06:13

5 Answers5

67

I'm assuming we're talking about the production environment.

When you change any of your javascripts or stylesheets in the production environment, you need to run rake assets:precompile; this task compiles and compresses the various .js and .css files and creates the application.js and application.css files that is loaded by your views.

It's possible that if you replaced jquery.autoresize.js with a version with an older timestamp, the precompile step might skip it, thinking the compiled version is up-to-date. You can avoid that by running rake assets:clean first, forcing it to rebuild everything in the public/assets directory from scratch.

benzado
  • 82,288
  • 22
  • 110
  • 138
  • Ahh, very interesting, thanks for your thoughts. I was actually doing this on my local development environment, and I never ran rake assets:precompile. So, perhaps that makes it behave differently? Do you think that the development environment would cause it to behave in the way that I described originally? – Aaron Gray Sep 06 '12 at 04:03
  • 2
    In the development environment, the hashed filenames are not used, so everything is based on file modification dates. (Do view-source in a browser to see the script links in the HTML header.) My guess is that in the dev environment, the replacement file had an older modification date, and so the browser was just using its cached version. Your edit updated the file's mod time, and that's why the browser finally fetched the new version. – benzado Sep 06 '12 at 18:10
  • Awesome. Thanks for helping me figure this out. I will modify the content of the question and stuff to better explain and give you credit for helping out. – Aaron Gray Sep 06 '12 at 19:02
  • 1
    RAILS_ENV=development bundle exec rake assets:clean, RAILS_ENV=development bundle exec rake assets:precompile, and RAILS_ENV=development bundle exec rails server is what finally did it for me. – Donato Jun 20 '15 at 21:52
65

Also try rake assets:clobber. This will totally reset everything and delete all compiled assets. In addition, I often need to set the environment before pushing to production by going: RAILS_ENV=production rake assets:precompile.

Dex
  • 12,527
  • 15
  • 69
  • 90
28

Rails automatically clears the cache for an individual file every time that the contents are edited. To clear the cache for a single file, simply open the file, edit a line of code, and re-save it. Rails will clear the cache for that file, and the browser will load the new file the next time the page is loaded.

The reason jquery.autoresize.js was using the old cached version of the file was because the old version was deleted and then the new version was copied and pasted with the same name into the same folder. Because the file itself was never edited, Rails continued to use the old file that was cached.

This is because the asset pipeline uses fingerprinting for the cache.

Fingerprinting is a technique that makes the name of a file dependent on the contents of the file. When the file contents change, the filename is also changed. For content that is static or infrequently changed, this provides an easy way to tell whether two versions of a file are identical, even across different servers or deployment dates.

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.

The technique that Rails uses for fingerprinting is to insert a hash of the content into the name, usually at the end. For example a CSS file global.css could be renamed with an MD5 digest of its contents:

global-908e25f4bf641868d8683022a5b62f54.css

So, if you delete a file you're referencing in the manifest, and then copy in a new file with the same name, the cache busting never occurs. When you edit the file, the fingerprinting kicks in, and a new hash is generated for the file name. This busts the cache for that file.

For the full story, see What is Fingerprinting and Why Should I Care?.

Dave Powers
  • 2,051
  • 2
  • 30
  • 34
Aaron Gray
  • 11,283
  • 7
  • 55
  • 61
  • 1
    I don't think this is correct. The fingerprint is based on the contents of the file. If you delete a file and replace it with a *different* one with the same name, you'll get a different fingerprint, and a different file name. – benzado Sep 05 '12 at 01:18
  • 1
    Thanks for chiming in. Have you tried this in one of your own projects recently? Because I can definitely confirm that when I created this question, the only way I could get the new file to be loaded by my browser was to edit a single line of code and resave it. If it is working for you by simply deleting the file and replacing it with a new one with the same name, I would love to hear about it. – Aaron Gray Sep 05 '12 at 22:26
  • I had a different asset pipeline issue, which is how I came across this question. You say "if you delete a file you're referencing in the manifest, and then copy in a new file with the same name, the cache busting never occurs"; that would *only* be true if the new/old file had *identical contents*, in which case who cares which version you have? If you're talking about production mode, you need to run `rake assets:precompile` to put the files in the `public/assets` directory; that should be the solution unless you've changed the default config. – benzado Sep 05 '12 at 23:15
  • 1
    Aaron is right, I had the same problem (in dev mode) and tried everything - `rake assets:clean`, then `rake assets:precompile`, as well as copying the new file over again and restarting the server. Nothing worked until I opened the new file, added a few dummy words at the end, then deleted them and saved the file. Rails is becoming too complex for it's own good - you know that's the case when simple things require complex steps to get done. – fullstackplus Feb 13 '14 at 14:33
  • 1
    Unfortunately not even @user906230's solution worked. Rails just continues to serve the old file, I've done everything besides debugging asset pipeline directly. If anybody has solved this please write a comment. – Michael Dec 09 '14 at 00:18
  • @Michael you need to clear you assets cache try running all of the following then recompiiging: Run the following commands: ``` rake assets:clean rake tmp:clear rake tmp:cache:clear rake cache:clear ``` – Darwayne Jan 16 '15 at 14:45
  • 2
    rather than editing the file, you can run `touch` on the file to update the timestamp on it. You can see if this is the issue by running `ls -l` and checking the modification date. – Ian Jun 16 '15 at 21:56
  • 1
    I ran into a similar problem and none of the above solutions helped. We have `application.css` include a single file (with sprockets' `*= require` syntax) which then includes further files using compass's `@import`. Changing files below the `@import` used to fix things but then after a precompile in dev once it started returning the cached precompiled version. I fixed this by _modifying `application.css`_ and rerequesting. That busted the cache and now it reloads appropriately. – jwadsack Jul 03 '15 at 22:50
  • 1
    Incredible that 4 years later this is still a problem. `rake tmp:clear` did nothing, I really had to add an empty line to the file to make it work. – Jonathan Allard Jul 04 '16 at 21:27
22

rake tmp:clear did the trick for me, I'm using less-rails.

Lucas Moulin
  • 2,450
  • 3
  • 32
  • 41
  • 2
    I have to do this as well to get browserify-rails to update, otherwise it will find and use old files that have since been deleted. `rails assets:clean` does not work for this. – Ryan Dec 03 '16 at 20:05
  • That is the only way for me to have the files properly rebuilt when they depend on changing environnement variables. Clean and Clobber seem not to be enough in such a case. – wallass Apr 13 '20 at 11:35
6

I use config.assets.version = '1.01019' in my application.rb to bust the entire cache. When I want to push a complete new version, I increment the version and that does the trick. This takes care of those edge cases where Rails does not recompile as asset for whatever reason.

user3670743
  • 294
  • 3
  • 8