1 介绍和应用
Page级别的cache,是用于cache整个action output保存为一个html,不需要经过action pack,
这是最快的缓存,不需要经过生成页面的过程,但是,这个只适用于所有用户察看的都是一样的页面,
这种缓存对CMS系统非常有效。
- class WeblogController < ActionController::Base
- caches_page :show, :new
- end
可以采用以下方法使之过期:
- class WeblogController < ActionController::Base
- def update
- List.update(params[:list][:id], params[:list])
- expire_page :action => "show", :id => params[:list][:id]
- redirect_to :action => "show", :id => params[:list][:id]
- end
- end
设置缓存目录:
Base.page_cache_directory = "/document/root"
默认设置是public目录(RAILS_ROOT + "/public")
设置缓存的扩展名
Base.page_cache_extension
2 源代码分析
- def self.included(base) #:nodoc:
- base.extend(ClassMethods)
- base.class_eval do
- # 缓存目录默认为public
- @@page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : ""
- cattr_accessor :page_cache_directory
- # 页面扩展默认为html
- @@page_cache_extension = '.html'
- cattr_accessor :page_cache_extension
- end
- end
- module ClassMethods
- # Expires the page that was cached with the +path+ as a key. Example:
- # expire_page "/lists/show"
- def expire_page(path)
- return unless perform_caching
- # 删除文件
- benchmark "Expired page: #{page_cache_file(path)}" do
- File.delete(page_cache_path(path)) if File.exist?(page_cache_path(path))
- end
- end
- # Manually cache the +content+ in the key determined by +path+. Example:
- # cache_page "I'm the cached content", "/lists/show"
- def cache_page(content, path) # nnd,取了这么一个名字跟caches_page很容易混起来,真受不了
- return unless perform_caching
- benchmark "Cached page: #{page_cache_file(path)}" do
- #创建目录写文件
- FileUtils.makedirs(File.dirname(page_cache_path(path)))
- File.open(page_cache_path(path), "wb+") { |f| f.write(content) }
- end
- end
- # Caches the +actions+ using the page-caching approach that'll store the cache in a path within the page_cache_directory that
- # matches the triggering url.
- #
- # Usage:
- #
- # # cache the index action
- # caches_page :index
- #
- # # cache the index action except for JSON requests
- # caches_page :index, :if => Proc.new { |c| !c.request.format.json? }
- def caches_page(*actions)
- return unless perform_caching
- options = actions.extract_options!
- # 利用after filter来实现
- # 这个after filter是前面提到的filter使用中的直接传proc的方式,而c就是controller
- after_filter({:only => actions}.merge(options)) { |c| c.cache_page }
- end
- private
- def page_cache_file(path)
- name = (path.empty? || path == "/") ? "/index" : URI.unescape(path.chomp('/')) #获取文件名
- name << page_cache_extension unless (name.split('/').last || name).include? '.' #获取名字
- return name
- end
- def page_cache_path(path) #获取cache的文件地址
- page_cache_directory + page_cache_file(path)
- end
- end
controller的实例方法:
- # Expires the page that was cached with the +options+ as a key. Example:
- # expire_page :controller => "lists", :action => "show"
- def expire_page(options = {})
- return unless perform_caching
- if options.is_a?(Hash)
- # 如果是一组方法,依次过期
- if options[:action].is_a?(Array)
- options[:action].dup.each do |action|
- self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :action => action)))
- end
- else
- # 如果是一个方法,过期
- self.class.expire_page(url_for(options.merge(:only_path => true, :skip_relative_url_root => true)))
- end
- else
- # 如果options不是hash
- self.class.expire_page(options)
- end
- end
- # Manually cache the +content+ in the key determined by +options+. If no content is provided, the contents of response.body is used
- # If no options are provided, the requested url is used. Example:
- # cache_page "I'm the cached content", :controller => "lists", :action => "show"
- def cache_page(content = nil, options = nil)
- return unless perform_caching && caching_allowed
- # 根据options计算路径,默认为request.path
- path = case options
- when Hash
- url_for(options.merge(:only_path => true, :skip_relative_url_root => true, :format => params[:format]))
- when String
- options
- else
- request.path
- end
- self.class.cache_page(content || response.body, path)
- end
- private
- def caching_allowed
- # 如果是get方法,如果是OK状态
- request.get? && response.headers['Status'].to_i == 200
- end
这里就有疑问:
rails怎么确定cache在什么时候去读取呢?
rails接受到请求后会先去public下查找相应的资源,
如果有那么会直接返回,
如果没有才会进入action_pack。