0
module ActionController #:nodoc:
0
- # To turn off all caching and sweeping, set Base.perform_caching = false.
0
+ # Caching is a cheap way of speeding up slow applications by keeping the result of calculations, renderings, and database calls
0
+ # around for subsequent requests. Action Controller affords you three approaches in varying levels of granularity: Page, Action, Fragment.
0
+ # You can read more about each approach and the sweeping assistance by clicking the modules below.
0
+ # Note: To turn off all caching and sweeping, set Base.perform_caching = false.
0
- def self.append_features(base)
0
+ def self.append_features(base)
#:nodoc:0
base.send(:include, Pages, Actions, Fragments, Sweeping)
0
@@ -41,6 +46,11 @@ module ActionController #:nodoc:
0
# Additionally, you can expire caches using Sweepers that act on changes in the model to determine when a cache is supposed to be
0
+ # == Setting the cache directory
0
+ # The cache directory should be the document root for the web server and is set using Base.page_cache_directory = "/document/root".
0
+ # For Rails, this directory has already been set to RAILS_ROOT + "/public".
0
def self.append_features(base) #:nodoc:
0
@@ -52,6 +62,16 @@ module ActionController #:nodoc:
0
+ # Expires the page that was cached with the +path+ as a key. Example:
0
+ # expire_page "/lists/show"
0
+ return unless perform_caching
0
+ File.delete(page_cache_path(path)) if File.exists?(page_cache_path(path))
0
+ logger.info "Expired page: #{path}" unless logger.nil?
0
+ # Manually cache the +content+ in the key determined by +path+. Example:
0
+ # cache_page "I'm the cached content", "/lists/show"
0
def cache_page(content, path)
0
return unless perform_caching
0
FileUtils.makedirs(File.dirname(page_cache_path(path)))
0
@@ -59,12 +79,8 @@ module ActionController #:nodoc:
0
logger.info "Cached page: #{path}" unless logger.nil?
0
- return unless perform_caching
0
- File.delete(page_cache_path(path)) if File.exists?(page_cache_path(path))
0
- logger.info "Expired page: #{path}" unless logger.nil?
0
+ # Caches the +actions+ using the page-caching approach that'll store the cache in a path within the page_cache_directory that
0
+ # matches the triggering url.
0
def caches_page(*actions)
0
return unless perform_caching
0
actions.each do |action|
0
@@ -72,15 +88,18 @@ module ActionController #:nodoc:
0
- def page_cache_path(path)
0
- page_cache_directory + path + '/index'
0
- page_cache_directory + path
0
+ def page_cache_path(path)
0
+ page_cache_directory + path + '/index'
0
+ page_cache_directory + path
0
+ # Expires the page that was cached with the +options+ as a key. Example:
0
+ # expire_page :controller => "lists", :action => "show"
0
def expire_page(options = {})
0
return unless perform_caching
0
if options[:action].is_a?(Array)
0
@@ -92,23 +111,18 @@ module ActionController #:nodoc:
0
- # Expires more than one page at the time. Example:
0
- # { :controller => "lists", :action => "public", :id => list_id },
0
- # { :controller => "lists", :action => "show", :id => list_id }
0
- def expire_pages(*options)
0
- options.each { |option| expire_page(option) }
0
+ # Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of @response.body is used
0
+ # If no options are provided, the current +options+ for this action is used. Example:
0
+ # cache_page "I'm the cached content", :controller => "lists", :action => "show"
0
def cache_page(content = nil, options = {})
0
return unless perform_caching && caching_allowed
0
self.class.cache_page(content || @response.body, url_for(options.merge({ :only_path => true })))
0
- !@request.method.post? and (@request.parameters.reject {|k, v| ['id', 'action', 'controller'].include?(k)}).empty?
0
+ !@request.method.post? && (@request.parameters.reject {|k, v| ['id', 'action', 'controller'].include?(k)}).empty?
0
# Action caching is similar to page caching by the fact that the entire output of the response is cached, but unlike page caching,
0
@@ -135,7 +149,7 @@ module ActionController #:nodoc:
0
base.send(:attr_accessor, :rendered_action_cache)
0
+ module ClassMethods
#:nodoc:0
def caches_action(*actions)
0
return unless perform_caching
0
around_filter(ActionCacheFilter.new(*actions))
0
@@ -198,7 +212,31 @@ module ActionController #:nodoc:
0
+ # In order to use the fragment caching, you need to designate where the caches should be stored. This is done by assigning a fragment store
0
+ # of which there are four different kinds:
0
+ # * FileStore: Keeps the fragments on disk in the +cache_path+, which works well for all types of environments and share the fragments for
0
+ # all the web server processes running off the same application directory.
0
+ # * MemoryStore: Keeps the fragments in memory, which is fine for WEBrick and for FCGI (if you don't care that each FCGI process holds its
0
+ # own fragment store). It's not suitable for CGI as the process is thrown away at the end of each request. It can potentially also take
0
+ # up a lot of memory since each process keeps all the caches in memory.
0
+ # * DRbStore: Keeps the fragments in the memory of a separate, shared DRb process. This works for all environments and only keeps one cache
0
+ # around for all processes, but requires that you run and manage a separate DRb process.
0
+ # * MemCachedStore: Works like DRbStore, but uses Danga's MemCached instead.
0
+ # Configuration examples (MemoryStore is the default):
0
+ # ActionController::Base.fragment_cache_store =
0
+ # ActionController::Caching::Fragments::MemoryStore.new
0
+ # ActionController::Base.fragment_cache_store =
0
+ # ActionController::Caching::Fragments::FileStore.new("/path/to/cache/directory")
0
+ # ActionController::Base.fragment_cache_store =
0
+ # ActionController::Caching::Fragments::DRbStore.new("druby://localhost:9192")
0
+ # ActionController::Base.fragment_cache_store =
0
+ # ActionController::Caching::Fragments::FileStore.new("localhost")
0
def self.append_features(base) #:nodoc:
0
@@ -246,41 +284,41 @@ module ActionController #:nodoc:
0
logger.info "Expired fragment: #{name}" unless logger.nil?
0
+ class MemoryStore
#:nodoc:0
+ @data
, @mutex = { }, Mutex.new0
def read(name, options = {}) #:nodoc:
0
+ @
mutex.synchronize { @data[name] }0
def write(name, value, options = {}) #:nodoc:
0
+ @
mutex.synchronize { @data[name] = value }0
def delete(name, options = {}) #:nodoc:
0
+ @
mutex.synchronize { @data.delete(name) }0
- class DRbStore < MemoryStore
0
+ class DRbStore < MemoryStore
#:nodoc:0
def initialize(address = 'druby://localhost:9192')
0
@data = DRbObject.new(nil, address)
0
- class MemCacheStore < MemoryStore
0
+ class MemCacheStore < MemoryStore
#:nodoc:0
def initialize(address = 'localhost')
0
@data = MemCache.new(address)
0
+ class FileStore
#:nodoc:0
def initialize(cache_path)
0
@cache_path = cache_path
0
@@ -317,38 +355,38 @@ module ActionController #:nodoc:
0
- module Sweeping #:nodoc:
0
+ # Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change.
0
+ # They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example:
0
+ # class ListSweeper < ActiveRecord::Observer
0
+ # def after_save(record)
0
+ # @list = record.is_a?(List) ? record : record.list
0
+ # def filter(controller)
0
+ # controller.expire_page(:controller => "lists", :action => %w( show public feed ), :id => @list.id)
0
+ # controller.expire_action(:controller => "lists", :action => "all")
0
+ # @list.shares.each { |share| controller.expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
0
+ # The sweeper is assigned on the controllers that wish to have its job performed using the <tt>cache_sweeper</tt> class method:
0
+ # class ListsController < ApplicationController
0
+ # caches_action :index, :show, :public, :feed
0
+ # cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ]
0
+ # In the example above, four actions are cached and three actions are responsible of expiring those caches.
0
def self.append_features(base) #:nodoc:
0
base.extend(ClassMethods)
0
- # Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change.
0
- # They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example:
0
- # class ListSweeper < ActiveRecord::Observer
0
- # def after_save(record)
0
- # @list = record.is_a?(List) ? record : record.list
0
- # def filter(controller)
0
- # controller.expire_page(:controller => "lists", :action => %w( show public feed ), :id => @list.id)
0
- # controller.expire_action(:controller => "lists", :action => "all")
0
- # @list.shares.each { |share| controller.expire_page(:controller => "lists", :action => "show", :id => share.url_key) }
0
- # The sweeper is assigned on the controllers that wish to have its job performed using the <tt>cache_sweeper</tt> class method:
0
- # class ListsController < ApplicationController
0
- # caches_action :index, :show, :public, :feed
0
- # cache_sweeper :list_sweeper, :only => [ :edit, :destroy, :share ]
0
- # In the example above, four actions are cached and three actions are responsible of expiring those caches.
0
+ module ClassMethods #:nodoc:
0
def cache_sweeper(*sweepers)
0
return unless perform_caching
0
configuration = sweepers.last.is_a?(Hash) ? sweepers.pop : {}
Comments
No one has commented yet.