Rails源代码分析(8):ActionController::Filter(2)

1 概述 

   昨天主要看了如何使用Filter,今天看看Filter的实现。

   这个Module实现中包含这几块:

  • 1 FilterChain 提供了管理Filter对象的方法
  • 2 Filter 所有Filter基类
  • 3 AroundFilter  继承自  Filter
  • 4 BeforeFilter  继承自  Filter
  • 5 AfterFilter  继承自  Filter

2 代码分析

2.1 FilterChain

  1. class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc:
  2.       #根据filter_type来添加一个filter到chain末尾
  3.       def append_filter_to_chain(filters, filter_type, &block)
  4.         pos = find_filter_append_position(filters, filter_type)
  5.         update_filter_chain(filters, filter_type, pos, &block)
  6.       end
  7.       #根据filter_type来添加一个filter到chain前面
  8.       def prepend_filter_to_chain(filters, filter_type, &block)
  9.         pos = find_filter_prepend_position(filters, filter_type)
  10.         update_filter_chain(filters, filter_type, pos, &block)
  11.       end
  12.       # 创建一个filter
  13.       def create_filters(filters, filter_type, &block)
  14.         filters, conditions = extract_options(filters, &block)
  15.         filters.map! { |filter| find_or_create_filter(filter, filter_type, conditions) }
  16.         filters
  17.       end
  18.       # 忽略一个filter
  19.       def skip_filter_in_chain(*filters, &test)
  20.         filters, conditions = extract_options(filters)
  21.         filters.each do |filter|
  22.           if callback = find(filter) then delete(callback) end
  23.         end if conditions.empty?
  24.         update_filter_in_chain(filters, :skip => conditions, &test)
  25.       end
  26.       private
  27.         # 插入一个filter具体方法
  28.         def update_filter_chain(filters, filter_type, pos, &block)
  29.           new_filters = create_filters(filters, filter_type, &block)
  30.           insert(pos, new_filters).flatten!
  31.         end
  32.         # 查找filter append的位置
  33.         def find_filter_append_position(filters, filter_type)
  34.           # appending an after filter puts it at the end of the call chain
  35.           # before and around filters go before the first after filter in the chain
  36.           unless filter_type == :after
  37.             each_with_index do |f,i|
  38.               return i if f.after?
  39.             end
  40.           end
  41.           return -1
  42.         end
  43.         # 查找filter prepend的位置
  44.         def find_filter_prepend_position(filters, filter_type)
  45.           # prepending a before or around filter puts it at the front of the call chain
  46.           # after filters go before the first after filter in the chain
  47.           if filter_type == :after
  48.             each_with_index do |f,i|
  49.               return i if f.after?
  50.             end
  51.             return -1
  52.           end
  53.           return 0
  54.         end
  55.         # 创建或者查找filter
  56.         def find_or_create_filter(filter, filter_type, options = {})
  57.           update_filter_in_chain([filter], options)
  58.           if found_filter = find(filter) { |f| f.type == filter_type }
  59.             found_filter
  60.           else
  61.             # 如果没有找到,那么根据filter方法来判断类别
  62.             filter_kind = case
  63.             when filter.respond_to?(:before) && filter_type == :before
  64.               :before
  65.             when filter.respond_to?(:after) && filter_type == :after
  66.               :after
  67.             else
  68.               :filter
  69.             end
  70.             # 根据filter类别来创建Filter
  71.             case filter_type
  72.             when :before
  73.               BeforeFilter.new(filter_kind, filter, options)
  74.             when :after
  75.               AfterFilter.new(filter_kind, filter, options)
  76.             else
  77.               AroundFilter.new(filter_kind, filter, options)
  78.             end
  79.           end
  80.         end
  81.         # 更新filter
  82.         def update_filter_in_chain(filters, options, &test)
  83.           filters.map! { |f| block_given? ? find(f, &test) : find(f) }
  84.           filters.compact!
  85.           map! do |filter|
  86.             if filters.include?(filter)
  87.               new_filter = filter.dup
  88.               new_filter.options.merge!(options)
  89.               new_filter
  90.             else
  91.               filter
  92.             end
  93.           end
  94.         end
  95.     end

2.2 Filter

  1.     class Filter < ActiveSupport::Callbacks::Callback #:nodoc:
  2.       def before?
  3.         self.class == BeforeFilter
  4.       end
  5.       def after?
  6.         self.class == AfterFilter
  7.       end
  8.       def around?
  9.         self.class == AroundFilter
  10.       end
  11.       private
  12.         def should_not_skip?(controller)
  13.           if options[:skip]
  14.             #:skip选项中不包含设定的方法就不能skip 
  15.             # 其中option[:skip]包含的结构也是一个包含:only :except的hash
  16.             !included_in_action?(controller, options[:skip]) 
  17.           else
  18.             true
  19.           end
  20.         end
  21.         def included_in_action?(controller, options) #判断该controller哪些是要加filter的
  22.           if options[:only]
  23.             Array(options[:only]).map(:to_s).include?(controller.action_name) #:only包含的是需要
  24.           elsif options[:except]
  25.             !Array(options[:except]).map(:to_s).include?(controller.action_name) #:except不用加
  26.           else
  27.             true
  28.           end
  29.         end
  30.         def should_run_callback?(controller) # 没有skip并且设定了的都要运行
  31.           should_not_skip?(controller) && included_in_action?(controller, options) && super
  32.         end
  33.     end

2.3 AroundFilter

 

  1.    class AroundFilter < Filter #:nodoc:
  2.       def type
  3.         :around
  4.       end
  5.       def call(controller, &block)
  6.         if should_run_callback?(controller)
  7.           method = filter_responds_to_before_and_after? ? around_proc : self.method
  8.           # For around_filter do |controller, action| 全部采用Proc方法运行
  9.           if method.is_a?(Proc) && method.arity == 2
  10.             evaluate_method(method, controller, block)
  11.           else
  12.             evaluate_method(method, controller, &block)
  13.           end
  14.         else
  15.           block.call
  16.         end
  17.       end
  18.       private
  19.         # 看看是否实现了before和after方法
  20.         def filter_responds_to_before_and_after?
  21.           method.respond_to?(:before) && method.respond_to?(:after)
  22.         end
  23.         # 将controller参数的before方法和after方法构建成Proc
  24.         def around_proc
  25.           Proc.new do |controller, action|
  26.             method.before(controller)
  27.             if controller.send!(:performed?)
  28.               controller.send!(:halt_filter_chain, method, :rendered_or_redirected# 如果rendered_or_redirected就停止
  29.             else
  30.               begin
  31.                 action.call
  32.               ensure
  33.                 method.after(controller)
  34.               end
  35.             end
  36.           end
  37.         end
  38.     end

2.4  BeforeFilter

  1.     class BeforeFilter < Filter #:nodoc:
  2.       def type
  3.         :before
  4.       end
  5.       def call(controller, &block)
  6.         super
  7.         if controller.send!(:performed?)
  8.           controller.send!(:halt_filter_chain, method, :rendered_or_redirected# 如果rendered_or_redirected就停止
  9.         end
  10.       end
  11.     end

2.5 AfterFilter

  1.     class AfterFilter < Filter #:nodoc:
  2.       def type
  3.         :after
  4.       end
  5.     end

3 总结

这次分析了几种Filter的具体代码实现,算是比较清楚了。

明天接着看如何加入到Controller

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值