Just monkey patched Sprockets in our Rails 3.2.9 app to override the Cache-Control header for html assets that we need to tweak more often in development, but that we don’t want to use digests/fingerprinting with:
Sprockets 2.x patch
if Rails.env.development?
module Sprockets
module Server
private
alias_method :sprockets_headers, :headers
def headers(env, asset, length)
sprockets_headers(env, asset, length).tap do |headers|
# cache-bust .html assets because in our case they are frequently AngularJS templates we need to tweak
if !path_fingerprint(env["PATH_INFO"]) && asset.pathname.basename.to_s['.html']
headers["Cache-Control"] = "max-age=0, private, must-revalidate"
end
end
end
end
end
end
Would the ability to configure “Cache-Control” and other headers (or add headers) in responses for assets in Sprockets be helpful to have available in Rails, or is it just assumed that if you need that level of control, you’ll fix it elsewhere with nginx, apache, etc.?
Why I’m asking is that Heroku shows here how to change expiry of actions:
but, I couldn’t find anywhere that talked about how to expire assets other than using digests/fingerprinting, until I came across server.rb in sprockets and realized that it didn’t look like it was possible without monkey patching or using another gem that would override the headers.
I also tried using digest in development and learned something: you can change an asset by moving one section of the file to another section and even though the file is thumbprinted/digested, sometimes the browser won’t reload it.
Basically, I changed config/environments/development.rb to use:
config.assets.debug = false
config.assets.digest = true
and much of the time if I move one section of the file to another part of the same file (and I tried in a few different ways), the browser (FF 17 in OS X) won’t reload the asset because it is still cached, even when I am forcing Sprockets to cache-bust via this patch in config/initializers/…/name_of_my_patch.rb
Sprockets 2.x patch to cache-bust non-fingerprinted angular template html in development
if Rails.env.development?
module Sprockets
module Server
private
# want to attempt to be compatible as much as possible so we'll call their headers method 'sprockets_headers' and then
# override just the headers we want. this may or may not work in future versions as this is a private method.
alias_method :sprockets_headers, :headers
def headers(env, asset, length)
sprockets_headers(env, asset, length).tap do |headers|
# both digested/thumbprinted and non-digested files seem to not refresh cache (at least with FF 17)
# so, use cache-busters for .../app/assets/**/*
if asset.pathname.to_s['/app/assets/']
puts "cache-busting #{asset.pathname.to_s} etag_header=#{headers["ETag"]} path_fingerprint(env[\"PATH_INFO\"])=#{path_fingerprint(env["PATH_INFO"])}"
headers["Cache-Control"] = "max-age=0, private, must-revalidate"
end
end
end
end
end
end
However, with that patch, if I comment out the following:
#config.assets.debug = false
#config.assets.digest = true
It seems to work as intended.
May not be a bug, really, but opened here for discussion, because it would seem that a file not changing its digest when it changes is a problem: https://github.com/sstephenson/sprockets/issues/399