17

I'm using Rails 3.2.13 and the Rails Asset Pipeline. I want to use the Asset Pipeline so I can use SASS and CoffeeScript and ERB for my assets and have the Pipeline automatically compile them, so I cannot turn off the pipeline in development. I am not precompiling assets in development ever and there is not even a public/assets/ directory.

However, when I make changes to an included file, such as to a _partial.html.erb file that is included (rendered) in a layout.html.erb file, without changing the file doing the including itself (in this example layout.html.erb), Sprockets doesn't detect the change and invalidate the cache, so I keep getting the same stale file. When I'm doing this in active development, I want to disable any caching of assets so I can get the changes on every request but I cannot figure out how to do this. I have set all of the following in my development.rb:

config.action_controller.perform_caching = false
config.action_dispatch.rack_cache =  nil
config.middleware.delete Rack::Cache
config.assets.debug = true
config.assets.compress = false
config.cache_classes = false

Still, even with this, files show up under tmp/cache/assets/ and tmp/cache/sass/ and changes are not available on future requests. Right now I have to manually delete those directories every time I want to see a change.

Unfortunately, the entire contents of the How Caching Works section of the RoR Guide for the Asset Pipeline is:

Sprockets uses the default Rails cache store to cache assets in development and production.

TODO: Add more about changing the default store.

So, how can I get Sprockets to compile assets on demand but not cache the results?

Denis de Bernardy
  • 75,850
  • 13
  • 131
  • 154
Old Pro
  • 24,624
  • 7
  • 58
  • 106

3 Answers3

30

Here's the magic incantation:

config.assets.cache_store = :null_store  # Disables the Asset cache
config.sass.cache = false  # Disable the SASS compiler cache

The asset pipeline has it's own instance of a cache and setting config.assets.cache = false does nothing, so you have to set its cache to be the null_store to disable it.

Even then, the SASS compiler has it's own cache, and if you need to disable it, you have to disable it separately.

Old Pro
  • 24,624
  • 7
  • 58
  • 106
  • This was absolutely killing me having to turn on & off file store cache when trying to test action caching logic. (without the actual caching part). Thank You. – CrazyVipa Nov 27 '13 at 13:57
  • This works for the first request on Rails 4 and then subsequent are cached in tmp/cache (off of Rails root, not /tmp). If you clear tmp/cache, it gets rebuilt. I wonder how to disable tmp/cache completely? – Cymen Apr 09 '14 at 22:59
  • 2
    @Cymen, caching works differently in Rails 4. Post a new question if you want to get help with that. – Old Pro Apr 10 '14 at 00:59
  • 4
    @OldPro Good point -- I was figuring most people end up here due to Google but might as well as so I did: http://stackoverflow.com/questions/22979839/disable-sprockets-asset-caching-in-development-on-rails-4 – Cymen Apr 10 '14 at 06:08
  • it really seems to be a bug, have you reported an issue? – brauliobo Sep 25 '14 at 20:49
1

I created the following gist (https://gist.github.com/metaskills/9028312) that does just this and found it is the only way that works for me.

# In config/initializers/sprockets.rb

require 'sprockets'
require 'sprockets/server'

Sprockets::Server.class_eval do

  private

  def headers_with_rails_env_check(*args)
    headers_without_rails_env_check(*args).tap do |headers|
      if Rails.env.development?
        headers["Cache-Control"]  = "no-cache"
        headers.delete "Last-Modified"
        headers.delete "ETag"
      end
    end
  end
  alias_method_chain :headers, :rails_env_check

end
MetaSkills
  • 1,954
  • 18
  • 15
0

The accepted answer is not doing it correctly and it degrades the performance in development by disabling cache totally. Answering your original question, you want changes to referenced files to invalidate the asset cache even if not included directly.

The solution is by simply declaring such dependency such that sprockets knows that the cache should be invalidated:

# layout.html.erb
<% depend_on Rails.root.join('app').join('views').join('_partial.html.erb') %>
# replace the above with the correct path, could also be relative but didn't try
hammady
  • 969
  • 1
  • 13
  • 22