天天看點

Rails源代碼分析(22):ActionController::Caching(6) Sweeping

Sweeping 清理cache:

  1.        class ListsController < ApplicationController
  2.          caches_action :index, :show, :public, :feed
  3.          cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ]
  4.        end

可以單獨定義:

  1. class ListSweeper < ActionController::Caching::Sweeper
  2.          observe List, Item
  3.          def after_lists_controller_update
  4.            #clear cache
  5.          end
  6.          def after_save(record)
  7.            list = record.is_a?(List) ? record : record.list
  8.            expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id)
  9.            expire_action(:controller => "lists", :action => "all")
  10.            list.shares.each { |share| expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
  11.          end
  12.        end

也可以定義在Module裡:

  1.        class ListsController < ApplicationController
  2.          caches_action :index, :show, :public, :feed
  3.          cache_sweeper OpenBar::Sweeper, :only => [ :edit, :destroy, :share ]
  4.        end

實作:

  1.     module Sweeping
  2.       def self.included(base) #:nodoc:
  3.         base.extend(ClassMethods)
  4.       end
  5.       module ClassMethods #:nodoc:
  6.         def cache_sweeper(*sweepers)
  7.           configuration = sweepers.extract_options!
  8.           sweepers.each do |sweeper|
  9.             ActiveRecord::Base.observers << sweeper if defined?(ActiveRecord) and defined?(ActiveRecord::Base) # 增加一個監聽器
  10.             sweeper_instance = (sweeper.is_a?(Symbol) ? Object.const_get(sweeper.to_s.classify) : sweeper).instance # 根據sweeper名字定義一個執行個體
  11.             if sweeper_instance.is_a?(Sweeper) # 增加為filter
  12.               around_filter(sweeper_instance, :only => configuration[:only])
  13.             else
  14.               after_filter(sweeper_instance, :only => configuration[:only])
  15.             end
  16.           end
  17.         end
  18.       end
  19.     end

關鍵看Sweeper的實作:

  1.     if defined?(ActiveRecord) and defined?(ActiveRecord::Observer)
  2.       class Sweeper < ActiveRecord::Observer #:nodoc:
  3.         attr_accessor :controller
  4.         def before(controller)
  5.           self.controller = controller
  6.           callback(:before) if controller.perform_caching
  7.         end
  8.         def after(controller)
  9.           callback(:after) if controller.perform_caching
  10.           # Clean up, so that the controller can be collected after this request
  11.           self.controller = nil
  12.         end
  13.         protected
  14.           # gets the action cache path for the given options.
  15.           def action_path_for(options)
  16.             ActionController::Caching::Actions::ActionCachePath.path_for(controller, options)
  17.           end
  18.           # Retrieve instance variables set in the controller.
  19.           def assigns(key)
  20.             controller.instance_variable_get("@#{key}")
  21.           end
  22.         private
  23.           def callback(timing)
  24.             # 生成 controller 回調方法的名字,以及目前正在調用的 action 的名字
  25.             controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
  26.             action_callback_method_name     = "#{controller_callback_method_name}_#{controller.action_name}"
  27.             # 如果有這些方法那麼調用
  28.             send!(controller_callback_method_name) if respond_to?(controller_callback_method_name, true)
  29.             send!(action_callback_method_name)     if respond_to?(action_callback_method_name, true)
  30.           end
  31.           def method_missing(method, *arguments)
  32.             return if @controller.nil?
  33.             @controller.send!(method, *arguments)
  34.           end
  35.       end
  36.     end

繼續閱讀