Rails源代码分析(9):ActionController::Filter(3)
来源:互联网 发布:筑龙投标软件 编辑:程序博客网 时间:2024/05/01 17:28
主要看看如何添加到ActionController的
1 ClassMethods
- module ClassMethods
- ########################################
- # The passed <tt>filters</tt> will be appended to the filter_chain and
- # will execute before the action on this controller is performed.
- def append_before_filter(*filters, &block)
- filter_chain.append_filter_to_chain(filters, :before, &block)
- end
- # The passed <tt>filters</tt> will be prepended to the filter_chain and
- # will execute before the action on this controller is performed.
- def prepend_before_filter(*filters, &block)
- filter_chain.prepend_filter_to_chain(filters, :before, &block)
- end
- # Shorthand for append_before_filter since it's the most common.
- alias :before_filter :append_before_filter
- # The passed <tt>filters</tt> will be appended to the array of filters
- # that run _after_ actions on this controller are performed.
- def append_after_filter(*filters, &block)
- filter_chain.append_filter_to_chain(filters, :after, &block)
- end
- # The passed <tt>filters</tt> will be prepended to the array of filters
- # that run _after_ actions on this controller are performed.
- def prepend_after_filter(*filters, &block)
- filter_chain.prepend_filter_to_chain(filters, :after, &block)
- end
- # Shorthand for append_after_filter since it's the most common.
- alias :after_filter :append_after_filter
- # If you <tt>append_around_filter A.new, B.new</tt>, the filter chain looks like
- #
- # B#before
- # A#before
- # # run the action
- # A#after
- # B#after
- #
- # With around filters which yield to the action block, +before+ and +after+
- # are the code before and after the yield.
- def append_around_filter(*filters, &block)
- filter_chain.append_filter_to_chain(filters, :around, &block)
- end
- # If you <tt>prepend_around_filter A.new, B.new</tt>, the filter chain looks like:
- #
- # A#before
- # B#before
- # # run the action
- # B#after
- # A#after
- #
- # With around filters which yield to the action block, +before+ and +after+
- # are the code before and after the yield.
- def prepend_around_filter(*filters, &block)
- filter_chain.prepend_filter_to_chain(filters, :around, &block)
- end
- # Shorthand for +append_around_filter+ since it's the most common.
- alias :around_filter :append_around_filter
- # Removes the specified filters from the +before+ filter chain. Note that this only works for skipping method-reference
- # filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out
- # of many sub-controllers need a different hierarchy.
- #
- # You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
- # just like when you apply the filters.
- def skip_before_filter(*filters)
- filter_chain.skip_filter_in_chain(*filters, :before?)
- end
- # Removes the specified filters from the +after+ filter chain. Note that this only works for skipping method-reference
- # filters, not procs. This is especially useful for managing the chain in inheritance hierarchies where only one out
- # of many sub-controllers need a different hierarchy.
- #
- # You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
- # just like when you apply the filters.
- def skip_after_filter(*filters)
- filter_chain.skip_filter_in_chain(*filters, :after?)
- end
- # Removes the specified filters from the filter chain. This only works for method reference (symbol)
- # filters, not procs. This method is different from skip_after_filter and skip_before_filter in that
- # it will match any before, after or yielding around filter.
- #
- # You can control the actions to skip the filter for with the <tt>:only</tt> and <tt>:except</tt> options,
- # just like when you apply the filters.
- def skip_filter(*filters)
- filter_chain.skip_filter_in_chain(*filters)
- end
- # Returns an array of Filter objects for this controller.
- def filter_chain
- if chain = read_inheritable_attribute('filter_chain')
- return chain
- else
- write_inheritable_attribute('filter_chain', FilterChain.new)
- return filter_chain
- end
- end
- # Returns all the before filters for this class and all its ancestors.
- # This method returns the actual filter that was assigned in the controller to maintain existing functionality.
- def before_filters #:nodoc:
- filter_chain.select(:before?).map(:method)
- end
- # Returns all the after filters for this class and all its ancestors.
- # This method returns the actual filter that was assigned in the controller to maintain existing functionality.
- def after_filters #:nodoc:
- filter_chain.select(:after?).map(:method)
- end
- end
2 InstanceMethods
用了两个alias_method_chain,前面看controller的时候知道了核心方法是process,然后process里调用perform_action方法。
这里等于是在process之前设置@before_filter_chain_aborted ,然后进入perform_action_with_filters
- module InstanceMethods # :nodoc:
- def self.included(base)
- base.class_eval do
- alias_method_chain :perform_action, :filters
- alias_method_chain :process, :filters
- end
- end
- protected
- def process_with_filters(request, response, method = :perform_action, *arguments) #:nodoc:
- @before_filter_chain_aborted = false
- process_without_filters(request, response, method, *arguments)
- end
- def perform_action_with_filters
- call_filters(self.class.filter_chain, 0, 0)
- end
- private
- def call_filters(chain, index, nesting)
- #1 调用before_filters方法 运行before和around filter
- index = run_before_filters(chain, index, nesting)
- aborted = @before_filter_chain_aborted
- #2 如果没有问题执行过render 或者 redirect 或者设置了@before_filter_chain_aborted变量为true 执行
- perform_action_without_filters unless performed? || aborted
- #3 设置了@before_filter_chain_aborted变量为true 返回
- return index if nesting != 0 || aborted
- #4 运行after_filter
- run_after_filters(chain, index)
- end
- def run_before_filters(chain, index, nesting)
- while chain[index]
- filter, index = chain[index], index
- break unless filter # end of call chain reached
- case filter
- # 先运行所有的before filter
- when BeforeFilter
- filter.call(self) # invoke before filter
- index = index.next
- break if @before_filter_chain_aborted
- when AroundFilter
- yielded = false
- filter.call(self) do
- yielded = true
- # all remaining before and around filters will be run in this call
- # 递归调用around filter
- index = call_filters(chain, index.next, nesting.next)
- end
- # 如果没有执行yield程序,运行结束
- halt_filter_chain(filter, :did_not_yield) unless yielded
- break
- else
- break # no before or around filters left
- end
- end
- index
- end
- def run_after_filters(chain, index)
- seen_after_filter = false
- while chain[index]
- filter, index = chain[index], index
- break unless filter # end of call chain reached
- case filter
- when AfterFilter
- seen_after_filter = true
- filter.call(self) # invoke after filter
- else
- # implementation error or someone has mucked with the filter chain
- raise ActionControllerError, "filter #{filter.inspect} was in the wrong place!" if seen_after_filter
- end
- index = index.next
- end
- index.next
- end
- # 这个方法在AroundFilter和BeforeFilter call都可能被调用
- def halt_filter_chain(filter, reason)
- @before_filter_chain_aborted = true
- logger.info "Filter chain halted as [#{filter.inspect}] #{reason}." if logger
- end
- end
- end
最后。。。完成
- def self.included(base)
- base.class_eval do
- extend ClassMethods
- include ActionController::Filters::InstanceMethods
- end
- end
终于结束了Filter
- Rails源代码分析(9):ActionController::Filter(3)
- Rails源代码分析(7):ActionController::Filter(1)
- Rails源代码分析(8):ActionController::Filter(2)
- Rails源代码分析(38):ActionController::Routing(9) 总结
- Rails源代码分析(19):ActionController::Caching(3) PageCache
- Rails源代码分析(32):ActionController::Routing(3) RouteSet
- Rails源代码分析(5):ActionController概览
- Rails源代码分析(6):ActionController::Flash
- Rails源代码分析(12):ActionController::Benchmarking
- Rails源代码分析(13):ActionController::Rescue
- Rails源代码分析(14):ActionController::MimeResponds
- Rails源代码分析(15):ActionController::Helpers
- Rails源代码分析(16):ActionController::Cookies
- Rails源代码分析(23):ActionController::Verification
- Rails源代码分析(24):ActionController::Streaming
- Rails源代码分析(25):ActionController::SessionManagement
- Rails源代码分析(27):ActionController::RecordIdentifier
- Rails源代码分析(28):ActionController::RequestForgeryProtection
- Struts 2与AJAX(第三部分)
- Creating a CAknEnumeratedTextPopupSettingItem-derived class to use dynamic data at runtime
- 装修日记第一季
- 点滴
- .net学习总结(4)之FreeTextBox使用详解
- Rails源代码分析(9):ActionController::Filter(3)
- 有向图的强连通
- 较好的JAVA学习网站汇总
- 三十四个超级经典小故事
- GDB使用手册
- 基于Eclipse开发OSGI的简单实例
- sql中把字符型转成整型
- CPU调度算法演示
- .net学习总结(5)之Gridview控件,智能搜索