How do I set a custom ETag value in a Rails controller response?
-
08-06-2021 - |
Question
For one controller (only), I'd like to use an ETag value generated outside of rails caching logic, and manage 304-vs-200 responses myself. It seems that nothing I do to set the ETag header works:
response.etag = myEtag
headers['ETag'] = myEtag
render :text => myText, :etag => myEtag
Rails always uses its own version.
I know I could disable caching app-wide, but I don't want that - just want to override it in the responses for one ActionController
subclass.
Solution
fresh_when
, etc. didn't quite suit my needs - in my case the solution was to refuse caching via
def caching_allowed?
false
end
then set just the headers['ETag']
member on my response - setting any of the .etag
options seems to cause Rails to MD5 All The Things.
OTHER TIPS
Also if you would like to overwrite it directly, you can set the etag value like below:
headers['ETag'] = 'xxxxxx'
Code reference from Rack (rack-1.6.11/lib/rack/etag.rb)
if etag_status?(status) && etag_body?(body) && !skip_caching?(headers)
original_body = body
digest, new_body = digest_body(body)
body = Rack::BodyProxy.new(new_body) do
original_body.close if original_body.respond_to?(:close)
end
headers[ETAG_STRING] = %(W/"#{digest}") if digest
end
private
def skip_caching?(headers)
(headers[CACHE_CONTROL] && headers[CACHE_CONTROL].include?('no-cache')) ||
headers.key?(ETAG_STRING) || headers.key?('Last-Modified')
end