cache-busting non-digest assets in sprockets in development a good idea? should headers in sprockets be configurable?

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