1 概述
昨天主要看了如何使用Filter,今天看看Filter的实现。
这个Module实现中包含这几块:
- 1 FilterChain 提供了管理Filter对象的方法
-
2 Filter 所有Filter基类
-
3 AroundFilter 继承自 Filter
-
4 BeforeFilter 继承自 Filter
-
5 AfterFilter 继承自 Filter
2 代码分析
2.1 FilterChain
- class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
- #根据filter_type来添加一个filter到chain末尾
- def append_filter_to_chain(filters, filter_type, &block)
- pos = find_filter_append_position(filters, filter_type)
- update_filter_chain(filters, filter_type, pos, &block)
- end
- #根据filter_type来添加一个filter到chain前面
- def prepend_filter_to_chain(filters, filter_type, &block)
- pos = find_filter_prepend_position(filters, filter_type)
- update_filter_chain(filters, filter_type, pos, &block)
- end
- # 创建一个filter
- def create_filters(filters, filter_type, &block)
- filters, conditions = extract_options(filters, &block)
- filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
- filters
- end
- # 忽略一个filter
- def skip_filter_in_chain(*filters, &test)
- filters, conditions = extract_options(filters)
- filters.each do |filter|
- if callback = find(filter) then delete(callback) end
- end if conditions.empty?
- update_filter_in_chain(filters, :skip => conditions, &test)
- end
- private
- # 插入一个filter具体方法
- def update_filter_chain(filters, filter_type, pos, &block)
- new_filters = create_filters(filters, filter_type, &block)
- insert(pos, new_filters).flatten!
- end
- # 查找filter append的位置
- def find_filter_append_position(filters, filter_type)
- # appending an after filter puts it at the end of the call chain
- # before and around filters go before the first after filter in the chain
- unless filter_type == :after
- each_with_index do |f,i|
- return i if f.after?
- end
- end
- return -1
- end
- # 查找filter prepend的位置
- def find_filter_prepend_position(filters, filter_type)
- # prepending a before or around filter puts it at the front of the call chain
- # after filters go before the first after filter in the chain
- if filter_type == :after
- each_with_index do |f,i|
- return i if f.after?
- end
- return -1
- end
- return 0
- end
- # 创建或者查找filter
- def find_or_create_filter(filter, filter_type, options = {})
- update_filter_in_chain([filter], options)
- if found_filter = find(filter) { |f| f.type == filter_type }
- found_filter
- else
- # 如果没有找到,那么根据filter方法来判断类别
- filter_kind = case
- when filter.respond_to?(:before) && filter_type == :before
- :before
- when filter.respond_to?(:after) && filter_type == :after
- :after
- else
- :filter
- end
- # 根据filter类别来创建Filter
- case filter_type
- when :before
- BeforeFilter.new(filter_kind, filter, options)
- when :after
- AfterFilter.new(filter_kind, filter, options)
- else
- AroundFilter.new(filter_kind, filter, options)
- end
- end
- end
- # 更新filter
- def update_filter_in_chain(filters, options, &test)
- filters.map! { |f| block_given? ? find(f, &test) : find(f) }
- filters.compact!
- map! do |filter|
- if filters.include?(filter)
- new_filter = filter.dup
- new_filter.options.merge!(options)
- new_filter
- else
- filter
- end
- end
- end
- end
2.2 Filter
- class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
- def before?
- self.class == BeforeFilter
- end
- def after?
- self.class == AfterFilter
- end
- def around?
- self.class == AroundFilter
- end
- private
- def should_not_skip?(controller)
- if options[:skip]
- #:skip选项中不包含设定的方法就不能skip
- # 其中option[:skip]包含的结构也是一个包含:only :except的hash
- !included_in_action?(controller, options[:skip])
- else
- true
- end
- end
- def included_in_action?(controller, options) #判断该controller哪些是要加filter的
- if options[:only]
- Array(options[:only]).map(:to_s).include?(controller.action_name) #:only包含的是需要
- elsif options[:except]
- !Array(options[:except]).map(:to_s).include?(controller.action_name) #:except不用加
- else
- true
- end
- end
- def should_run_callback?(controller) # 没有skip并且设定了的都要运行
- should_not_skip?(controller) && included_in_action?(controller, options) && super
- end
- end
2.3 AroundFilter
- class AroundFilter < Filter #:nodoc:
- def type
- :around
- end
- def call(controller, &block)
- if should_run_callback?(controller)
- method = filter_responds_to_before_and_after? ? around_proc : self.method
- # For around_filter do |controller, action| 全部采用Proc方法运行
- if method.is_a?(Proc) && method.arity == 2
- evaluate_method(method, controller, block)
- else
- evaluate_method(method, controller, &block)
- end
- else
- block.call
- end
- end
- private
- # 看看是否实现了before和after方法
- def filter_responds_to_before_and_after?
- method.respond_to?(:before) && method.respond_to?(:after)
- end
- # 将controller参数的before方法和after方法构建成Proc
- def around_proc
- Proc.new do |controller, action|
- method.before(controller)
- if controller.send!(:performed?)
- controller.send!(:halt_filter_chain, method, :rendered_or_redirected) # 如果rendered_or_redirected就停止
- else
- begin
- action.call
- ensure
- method.after(controller)
- end
- end
- end
- end
- end
2.4 BeforeFilter
- class BeforeFilter < Filter #:nodoc:
- def type
- :before
- end
- def call(controller, &block)
- super
- if controller.send!(:performed?)
- controller.send!(:halt_filter_chain, method, :rendered_or_redirected) # 如果rendered_or_redirected就停止
- end
- end
- end
2.5 AfterFilter
- class AfterFilter < Filter #:nodoc:
- def type
- :after
- end
- end
3 总结
这次分析了几种Filter的具体代码实现,算是比较清楚了。
明天接着看如何加入到Controller