How do I prevent Rails 3.1 from caching static assets to Rails.cache?

▼魔方 西西 提交于 2019-11-28 23:14:03

The original poster wanted to prevent static assets from getting into the general Rails cache, which led them to want to disable the Rack::Cache. Rather than doing this, the better solution is to configure Rack::Cache to use a separate cache than the general Rails cache.

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: https://devcenter.heroku.com/articles/rack-cache-memcached-static-assets-rails31

Jack Chu

After a lot of experimentation, I've ended up doing this in my config/application.rb:

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

What this does is add a Rack::Static rack middleware before requests to Rack::Cache. The Rack::Static middleware serves up urls with a matching prefix to a root directory. Here I'm giving config.assets.prefix as my url prefix which defaults to '/assets.' I'm setting the root to the 'public' directory.

Requests for this path:

/assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

should find it in this file:

public/assets/jquery-e8da439bbc8fd345e34ac57c6a216318.min.js

This should serve any assets directly out of the public/assets directory instead of hitting Rails::Cache at all, which will prevent it from storing the assets in the Rails cache_store. This will only work if you run the 'rake assets:precompile' in production, otherwise there will be no precompiled assets in 'public/assets'.

You can turn off caching of asset pipeline files while leaving other caching in place with:

config.assets.cache_store = :null_store

That should keep Sprockets from caching anything.

Another way to solve the same problem and this issue is to use the ActionDispatch::Static middleware instead of Rack::Static like this:

if !Rails.env.development? && !Rails.env.test?
  config.middleware.insert_before Rack::Cache, ::ActionDispatch::Static, 'public', config.static_cache_control
end

What's the difference between Rack::Static and ActionDispatch::Static you ask?

  • Rack::Static takes an array of url prefixes to check against the request url. So in our case, it will only check for files if the request path begins with '/assets'.

  • ActionDispatch::Static will check for the existence of the file in 'public' on every GET/HEAD request, regardless of path.

  • Rack::Static doesn't check for the file first, it calls Rack::File.new on the file, so if it doesn't exist it will return a 404, it will not pass the request down the middleware chain.

  • If ActionDispatch::Static doesn't find the file in its path, it'll continue down the rack middleware chain (the rest of the Rails stack).

In the end, whatever ActionDispatch::Static doesn't find in 'public' it'll just pass on down to the Rails stack. So Rails will end up serving the assets that ActionDispatch::Static can't find. This solves my issue of assets not being found by Rack::Cache, but it's also more resource intensive since every request will trigger a file check.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!