One problem that tripped me up with http caching in rails was invalidating client http caches when a template changes and you're doing conditional etags based on an object's updated at timestamp. So basically when you do fresh_when(object), your rails app basically will only tell an http client this thing is stale if the object's updated_at timestamp changes. It doesn't take into account if the actually view code changes. Even worse, when your assets get recompiled (app-123.css is now app-234.css) and the old ones don't exist anymore, your app breaks.
I wrote about a way to fix that with a little gem I made:
Declared ETags, together with Russian Doll caching, take the next step: automatically mixing your template and asset versions into your ETags.
To include the template's version in the ETag:
# Incorporate the cache version for this action into our ETag.
# This allows template changes to bubble up into HTTP cache
# freshness and bust browser caches when we make changes.
etag do
begin
CacheDigests::TemplateDigestor.digest(
"#{controller_name}/#{action_name}",
request.format.try(:to_sym), lookup_context)
rescue ActionView::MissingTemplate => e
'' # Ignore missing templates
end
end
Similarly, for your JavaScript and CSS assets:
ASSET_FRESHNESS_PATHS = %w( application.js application.css )
# HTML pages cached by the browser should be updated whenever we change
# our assets, so we include application.css and application.js digests
# in ETags for HTML pages.
etag do
if request.format.try(:html?)
ASSET_FRESHNESS_PATHS.map { |p| asset_digest_for_etag(p) }.join('-')
end
end
# Check precompiled asset manifest (production) or compute the digest (dev).
def asset_digest_for_etag(logical_path)
if manifest = Rails.application.config.assets.digests
manifest[logical_path]
else
Rails.application.assets[logical_path].digest
end
end
This avoids the need to use global versions that blow all browser caches. Neatly contains the scope of "freshness fallout" when you tweak a view and deploy.
4 comments
[ 3.0 ms ] story [ 18.0 ms ] threadOne problem that tripped me up with http caching in rails was invalidating client http caches when a template changes and you're doing conditional etags based on an object's updated at timestamp. So basically when you do fresh_when(object), your rails app basically will only tell an http client this thing is stale if the object's updated_at timestamp changes. It doesn't take into account if the actually view code changes. Even worse, when your assets get recompiled (app-123.css is now app-234.css) and the old ones don't exist anymore, your app breaks.
I wrote about a way to fix that with a little gem I made:
http://ninjasandrobots.com/rails-caching-a-problem-with-etag...
Declared ETags, together with Russian Doll caching, take the next step: automatically mixing your template and asset versions into your ETags.
To include the template's version in the ETag:
Similarly, for your JavaScript and CSS assets: This avoids the need to use global versions that blow all browser caches. Neatly contains the scope of "freshness fallout" when you tweak a view and deploy.Oh, and the famed 'russian doll' caching: https://github.com/rails/cache_digests