Would love to get some feedback on this...
No doubt, 5 minutes after posting this, someone will tell me of the built-in Rails way of doing this, but alas I could not find it.
Usage looks like this:
1
2 class PeopleController < ApplicationController
3 caches_action :show, :for => 1.hour, :cache_path => Proc.new { |c| "people/#{c.params[:id]}_for_#{Person.logged_in.id}" }
4 end
The ":for => 1.hour" part is where the magic happens.
Basically, this bit of code adds a before_filter that checks the last modified time of the cache entry, and expires it if it is older than the specified time period.
1
2 module ActionController
3 module Caching
4 module Fragments
5
6
7 def expire_fragment_by_mtime(key, age=nil, &block)
8 block = Proc.new { |m| m < age.ago } unless block_given?
9 if (m = cache_store.mtime(fragment_cache_key(key))) and block.call(m)
10 expire_fragment(key)
11 end
12 end
13 end
14 module Actions
15 module ClassMethods
16
17
18
19 def caches_action_with_for(*actions)
20 original_actions = actions.clone
21 options = actions.extract_options!
22 if for_time = options.delete(:for)
23 cache_path = options[:cache_path]
24 before_filter do |controller|
25 cache_path = cache_path.call(controller) if cache_path.respond_to?(:call)
26 controller.expire_fragment_by_mtime(cache_path, for_time)
27 end
28 end
29 caches_action_without_for(*original_actions)
30 end
31 alias_method_chain :caches_action, :for
32 end
33 end
34 end
35 end
36
37
38
39
40 module ActiveSupport
41 module Cache
42 class FileStore
43 def mtime(name)
44 File.mtime(real_file_path(name)) rescue nil
45 end
46 end
47 end
48 end