user572896
user572896

Reputation:

When does Rails 3.2 use the pages that it caches to disk?

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

Answers (2)

user572896
user572896

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

Frederick Cheung
Frederick Cheung

Reputation: 84132

There are two forms of caching going on:

  • Rack::Cache
  • Page caching

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

Related Questions