Good afternoon,
I've run into some issues trying to combine HTTP caching with Rack::Cache and action caching (on my Heroku-hosted app).
Using them individually, it seems to be working. With action caching enabled, the page loading is snappy, and the log would suggest it is caching. With HTTP caching in the controllers (eTag, last_modified and fresh_when) the proper headers appear to be set.
However, when I try to combine the two, it appears to be action caching, but the HTTP headers are always max_age: 0, must_revalidate. Why is this? Am I doing something wrong?
For example, here's the code in my "home" action:
class StaticPagesController < ApplicationController
layout 'public'
caches_action :about, :contact, ......, :home, .....
......
def home
last_modified = File.mtime("#{Rails.root}/app/views/static_pages/home.html.haml")
fresh_when last_modified: last_modified , public: true, etag: last_modified
expires_in 10.seconds, :public => true
end
For all intents and purposes, this should have a public cache-control tag with max-age 10 no?
$ curl -I http://myapp-staging.herokuapp.com/
HTTP/1.1 200 OK
Cache-Control: max-age=0, private, must-revalidate
Content-Type: text/html; charset=utf-8
Date: Thu, 24 May 2012 06:50:45 GMT
Etag: "997dacac05aa4c73f5a6861c9f5a9db0"
Status: 200 OK
Vary: Accept-Encoding
X-Rack-Cache: stale, invalid
X-Request-Id: 078d86423f234da1ac41b418825618c2
X-Runtime: 0.005902
X-Ua-Compatible: IE=Edge,chrome=1
Connection: keep-alive
Config Info:
# Use a different cache store in production
config.cache_store = :dalli_store
config.action_dispatch.rack_cache = {
:verbose => true,
:metastore => "memcached://#{ENV['MEMCACHE_SERVERS']}",
:entitystore => "memcached://#{ENV['MEMCACHE_SERVERS']}"#,
}
In my mind, you should be able to use action caching as well as a reverse proxy correct? I know that they do fairly similar things (if the page changes, both the proxy and the action cache will be invalid and need to be regenerated), but I feel I should be able to have both in there. Or should I get rid of one?
UPDATE
Thanks for the answer below! It seems to work. But to avoid having to write set_XXX_cache_header methods for every controller action, do you see any reason why this wouldn't work?
before_filter :set_http_cache_headers
.....
def set_http_cache_headers
expires_in 10.seconds, :public => true
last_modified = File.mtime("#{Rails.root}/app/views/static_pages/#{params[:action]}.html.haml")
fresh_when last_modified: last_modified , public: true, etag: last_modified
end
When you use action caching, only the response body and content type is cached. Any other changes to the response will not happen on subsequent requests.
However, action caching will run any before filters even when the action itself is cached.
So, you can do something like this: