Reputation:
In an old Rails project page caching works as I expect from reading doc online, in Rails 3.1 / 3.2 it does not work the same way. It appears like Rails writes the pages to disk but never uses them (and so I assume it's caching pages in memory).
(Please bear with my long explanation, it's not complex just thorough...)
In a new Rails 3.2.2 app I have the following:
class HomeController < ApplicationController
caches_page :index
def index
expires_in 1.year, :private => false, :public => true
end
end
When I start my server in production and visit localhost I see:
cache: [GET /] miss, store
Started GET "/" for 127.0.0.1 at 2012-03-02 12:19:22 -0500
Processing by HomeController#index as HTML
Rendered home/index.html.erb within layouts/application (20.0ms)
Write page /home/sheldon/Dev/rails-3.2-app/public/index.html (0.4ms)
Completed 200 OK in 30ms (Views: 28.7ms | ActiveRecord: 0.0ms)
The file public/index.html appears on disk.
I'm using Firefox, if I ctrl+r or shift+ctrl+r I see:
cache: [GET /] fresh
[2012-03-02 12:21:39] WARN Could not determine content-length of response body. Set content-length of the response or set Response#chunked = true
If I edit the public/index.html file directly and hit ctrl+r or ctrl+shift+r I do not see the changes I've made to the file.
If I open a rails console and type Rails.cache.clear
I see:
=> ["/home/sheldon/Dev/rails-3.2-app/tmp/cache/9F4", "/home/sheldon/Dev/rails-3.2-app/tmp/cache/A9A"]
Now if I ctrl+r or ctrl+shift+r I see:
cache: [GET /] miss, store
Started GET "/" for 127.0.0.1 at 2012-03-02 12:37:04 -0500
Processing by HomeController#index as HTML
Rendered home/index.html.erb within layouts/application (0.0ms)
Write page /home/sheldon/Dev/rails-3.2-app/public/index.html (0.3ms)
Completed 200 OK in 2ms (Views: 1.2ms | ActiveRecord: 0.0ms)
And my changes to public/index.html are overwritten.
So it appears that public/index.html is never used.
If I edit the html file found in tmp/cache (in the console output above) and then ctrl+r or ctrl+shift+r I still do not see the changes I make directly to the tmp/cache file.
If I set config.cache_store = :file_store, Rails.public_path + "/cache"
the behaviour seems identical.
In Getting Started Rails Guide it says "Rails will deliver any static file in the public directory in preference to any dynamic content we generate from the controllers", but clearly this is not the case.
It seems like the page is cached in memory only and the files on disk aren't used... can anyone explain what is happening here and how I can cache pages on disk? It's not practical to cache all pages in memory. Thanks!
Upvotes: 4
Views: 1160
Reputation:
This was my attempted setup that I thought would do everything I wanted:
config.cache_store = :dalli_store, '127.0.0.1:11211'
config.middleware.delete Rack::Cache
config.middleware.use Rack::Cache,
:verbose => true,
:metastore => "memcached://127.0.0.1:11211/meta",
:entitystore => "file:#{Rails.root}/tmp/cache/rack/body"
config.action_controller.page_cache_directory = "#{Rails.root}/public/cache"
This seemed to work at first but I started to receive blank pages when a page was stale but valid (i.e. returning 304). I couldn't find a way around this, so... I don't know how to setup Rack::Cache to use a filestore while still leaving the option to use memcached with Rails.cache.
I'm now using Rails page caching for most of the site. Unfortunately this has the drawback of maintaining complicated sweepers and it also means pages that require query params will have to be cached in memory with expires_in, and fresh_when/stale.
Upvotes: 0
Reputation: 84132
There are two forms of caching going on:
Rack::Cache
Page caching is what caches_page
turns on, and writes files in /public. Page caching is dumb in that once that file is there it will keep getting served until something removes it. The upside is that it is very fast: you normally configure nginx, apache etc. to serve those files directly without the request ever hitting ruby. If you're not running nginx or apache then that file will only get served if rails is configured to serve static assets, which is off by default in production (see config.serve_static_assets
)
Rack::Cache
is an http aware cache, so it can handle expiry times, tells intermediate caches that may exist between you and the user what they can cache etc. It stores its cached data in whatever store you've configured Rails.cache
to be (file store by the looks of it). Any request does still have to go via ruby, so that Rack::Cache can decide whether to return the cached data or whether to let the request continue up to your application.
Upvotes: 2