3.1: Preventing assets from being cached in Rails.cache/Rack::Cache #2468

kamui opened this Issue Aug 8, 2011 · 16 comments


None yet
kamui commented Aug 8, 2011

I have a Rails 3.1 app on Heroku that uses Cloudflare as a CDN. Cloudflare is a DNS based CDN, so you use their DNS servers for your domain. When a static asset is first requested, Cloudflare requests it from your web app, caches the file in it's CDN and then subsequent requests get served from the CDN. It's similar to how Amazon Cloudfront works, except that your asset host remains your app's host instead of some other domain name.

The issue arrises when you use:

config.action_controller.perform_caching = true

In 3.1, Rack::Cache seems to automatically use your config.cache_store to store assets/html fragments. Since Cloudflare is handling my asset caching, I want to stop Rack::Cache from caching assets to Rails.cache. In my case, I'm using redis-store, so my RedisToGo instance is being filled up quickly with static assets from Rack::Cache. This is kind of redundant since my CDN is going to be serving a majority of these requests. The few asset requests that Rails should get should be from Cloudflare, so it's fine if Rails serves this directly from the precompiled assets instead of from the Rails.cache.

I've considered disabling the Rack::Cache middleware, but then I lose out on page/action/fragment controller caching. I've tried setting my config.static_cache_control to private or no-cache, but no-cache would also prevent user browers from caching the assets and both still store assets in the cache.

I'm at a loss here. For now I've increased my RedisToGo instance, but that's not a good long term strategy.

kamui commented Aug 10, 2011

After some research and experimentation, I've ended up doing this in my config/application.rb for now:

if !Rails.env.development? && !Rails.env.test?
  config.middleware.insert_before Rack::Cache, Rack::Static, urls: [config.assets.prefix], root: 'public'

I've have a more detailed explanation in a blog post and also StackOverflow.

mdi commented Oct 6, 2011

I'm having/seeing the same issue. I would say this is a huge problem.


How do i check the list of assets cached in the Rails cache?

chewi commented Feb 24, 2012

The proposed workaround seems to conflict with Dragonfly. Plus not only are these assets being needlessly cached but it seems to prevent the assets from even being found at all in some instances. I haven't worked out exactly what conditions are causing this but I am seeing "The page you were looking for doesn't exist" for assets that are blatantly present under public/assets.

ehudros commented Apr 30, 2012

+1 for fixing this. It's extremely strange (and quite unnecessary) to store static assets in the application cache by default.


Rack Cache should be configured differently for entity storage vs meta storage. Rack::Cache has two different storage areas: meta and entity stores. The metastore keeps high level information about each cache entry including HTTP request and response headers. This area stores small chunks of data that is accessed at a high frequency. The entitystore caches the response body content which can be a relatively large amount of data though it is accessed less frequently than the metastore

The below configuration caches the metastore info in memcached but the actual body of the assets to the file system.

Using memcached gem:

  config.action_dispatch.rack_cache = {
    :metastore    => 'memcached://localhost:11211/meta',
    :entitystore  => 'file:tmp/cache/rack/body',
    :allow_reload => false

Using dalli gem

config.action_dispatch.rack_cache = {
  :metastore    => Dalli::Client.new,
  :entitystore  => 'file:tmp/cache/rack/body',
  :allow_reload => false

By the way this configuration is the recommendation for Heroku:



I've considered disabling the Rack::Cache middleware, but then I lose out on page/action/fragment controller caching

Rack::Cache has nothing to do with action or fragment caching.

kamui commented Jun 28, 2012

@twinturbo I meant that indirectly.

config.action_controller.perform_caching = true

This enables action/page/fragment caching and also turns on Rack::Cache in production. At the time, I didn't see another way of disabling Rack::Cache from storing static assets.

It looks like you can also disable Rack::Cache this way:

config.action_dispatch.rack_cache =  nil

but I didn't want to disable Rack::Cache entirely, I just wanted to disable it from storing static assets. But @joe1chen's suggestion seems like a good solution.

themgt commented Jul 5, 2012

@kamui +1 for fixing this - I have been seeing Rails make copies of compiled assets in its cache folder in production, and at time these actually get corrupted somehow, so the wrong files get served - I'm guessing some sort of threadsafe issue, but I don't see any benefit in trying to track it down since making a file cache of files is just wasting resources. Your fix to force them to be served with Rack::Static appears to work perfectly

An out of the box rails app in production is taking JS/CSS/image files and copying them into a file-based "cache". It seems like this should be disabled


I don't consider this a bug in Rails, for several reasons:

  • You could consider your Redis instance as an LRU cache, therefore the assets would get evicted once there is memory pressure.
  • It would only deal with Rack::Cache. Users might still need to configure other HTTP caches separately. Or maybe not: for example nginx by default evicts unused resources after 10 minutes.
  • We can't solve this by headers; that would cause the CDN to serve the assets with the wrong headers too.

This situation could be improved by documentation. It would be good to have something in the asset pipeline guide along the lines of "if your assets are being served by a CDN, ensure they don't stick around in your HTTP cache forever (by LRU eviction, configuration, etc)".


I've written some documentation and put it in docrails here: rails/docrails@e85cb2d


Nice one Steve. Think we can close this then.

@jonleighton jonleighton closed this Nov 9, 2012

Thanks for the note!

@kennyj kennyj pushed a commit to kennyj/rails that referenced this issue Nov 13, 2012
@steveklabnik steveklabnik Add note about asset pipeline and CDNs.
Fixes #2468.
seigel commented Apr 17, 2015

Just a note where one might get concerned is when your asset that is being cached is > 1MB. Memcached can only hold 1MB of cached data in a bucket. This will lead to all sorts of hilarity.


@seigel The default maximum item size in Memcached is 1 MB. Since Memcached 1.4.2, this maximum item size can be configured and increased.


memcached -I 10m  # Allow objects up to 10MB
seigel commented Apr 17, 2015

Yup. Just Putting the comment in there for the person who is maybe using a stock deploy or a service from Heroku or something and is finding that their app is crashing and they have no idea why. That is how we got to this point :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment