aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_controller/caching/sweeping.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_controller/caching/sweeping.rb')
-rw-r--r--actionpack/lib/action_controller/caching/sweeping.rb90
1 files changed, 90 insertions, 0 deletions
diff --git a/actionpack/lib/action_controller/caching/sweeping.rb b/actionpack/lib/action_controller/caching/sweeping.rb
new file mode 100644
index 0000000000..eda4459cda
--- /dev/null
+++ b/actionpack/lib/action_controller/caching/sweeping.rb
@@ -0,0 +1,90 @@
+module ActionController #:nodoc:
+ module Caching
+ # Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change.
+ # They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example:
+ #
+ # class ListSweeper < ActionController::Caching::Sweeper
+ # observe List, Item
+ #
+ # def after_save(record)
+ # list = record.is_a?(List) ? record : record.list
+ # expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id)
+ # expire_action(:controller => "lists", :action => "all")
+ # list.shares.each { |share| expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
+ # end
+ # end
+ #
+ # The sweeper is assigned in the controllers that wish to have its job performed using the <tt>cache_sweeper</tt> class method:
+ #
+ # class ListsController < ApplicationController
+ # caches_action :index, :show, :public, :feed
+ # cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ]
+ # end
+ #
+ # In the example above, four actions are cached and three actions are responsible for expiring those caches.
+ module Sweeping
+ def self.included(base) #:nodoc:
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods #:nodoc:
+ def cache_sweeper(*sweepers)
+ return unless perform_caching
+ configuration = sweepers.extract_options!
+ sweepers.each do |sweeper|
+ ActiveRecord::Base.observers << sweeper if defined?(ActiveRecord) and defined?(ActiveRecord::Base)
+ sweeper_instance = Object.const_get(Inflector.classify(sweeper)).instance
+
+ if sweeper_instance.is_a?(Sweeper)
+ around_filter(sweeper_instance, :only => configuration[:only])
+ else
+ after_filter(sweeper_instance, :only => configuration[:only])
+ end
+ end
+ end
+ end
+ end
+
+ if defined?(ActiveRecord) and defined?(ActiveRecord::Observer)
+ class Sweeper < ActiveRecord::Observer #:nodoc:
+ attr_accessor :controller
+
+ def before(controller)
+ self.controller = controller
+ callback(:before)
+ end
+
+ def after(controller)
+ callback(:after)
+ # Clean up, so that the controller can be collected after this request
+ self.controller = nil
+ end
+
+ protected
+ # gets the action cache path for the given options.
+ def action_path_for(options)
+ ActionController::Caching::Actions::ActionCachePath.path_for(controller, options)
+ end
+
+ # Retrieve instance variables set in the controller.
+ def assigns(key)
+ controller.instance_variable_get("@#{key}")
+ end
+
+ private
+ def callback(timing)
+ controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
+ action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}"
+
+ send!(controller_callback_method_name) if respond_to?(controller_callback_method_name, true)
+ send!(action_callback_method_name) if respond_to?(action_callback_method_name, true)
+ end
+
+ def method_missing(method, *arguments)
+ return if @controller.nil?
+ @controller.send!(method, *arguments)
+ end
+ end
+ end
+ end
+end \ No newline at end of file