Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: b4b0fddb24
Fetching contributors…

Cannot retrieve contributors at this time

file 97 lines (86 sloc) 3.975 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
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.
    #
    # You can also name an explicit class in the declaration of a sweeper, which is needed if the sweeper is in a module:
    #
    # class ListsController < ApplicationController
    # caches_action :index, :show, :public, :feed
    # cache_sweeper OpenBar::Sweeper, :only => [ :edit, :destroy, :share ]
    # end
    module Sweeping
      extend ActiveSupport::Concern

      module ClassMethods #:nodoc:
        def cache_sweeper(*sweepers)
          configuration = sweepers.extract_options!

          sweepers.each do |sweeper|
            ActiveRecord::Base.observers << sweeper if defined?(ActiveRecord) and defined?(ActiveRecord::Base)
            sweeper_instance = (sweeper.is_a?(Symbol) ? Object.const_get(sweeper.to_s.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) if controller.perform_caching
          true # before method from sweeper should always return true
        end

        def after(controller)
          self.controller = controller
          callback(:after) if controller.perform_caching
          # 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)
            Actions::ActionCachePath.new(controller, options).path
          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, &block)
            super unless @controller
            @controller.__send__(method, *arguments, &block)
          end
      end
    end
  end
end
Something went wrong with that request. Please try again.