Filter类似于钩子方法,
在调用某个controller方法之前、之后或者包围调用这个方法,很有用的方法,利用这个可以很大幅度的减少代码量。
- 1 先研究下种类:
- 1.1 before_filter
- 1.1 before_filter
多用于验证之类的
# before_filter :verify_credentials
#
# private
# def verify_credentials
# # make sure the user is allowed into the vault
# end
- 1.2 after_filter
- 1.2 after_filter
多用于log之类的后续处理
# class OutputCompressionFilter
# def self.filter(controller)
# controller.response.body = compress(controller.response.body)
# end
# end
#
# class NewspaperController < ActionController::Base
# after_filter OutputCompressionFilter
# end
- 1.3 around_filter
- 1.3 around_filter
一般用户来捕捉异常,按照2所说使用方法可以包括:
- 1.3.1 传递filter方法名
- 1.3.1 传递filter方法名
# around_filter :catch_exceptions
#
# private
# def catch_exceptions
# yield
# rescue => exception
# logger.debug "Caught exception! #{exception}"
# raise
# end
- 1.3.2 传递外部Filter类
- 这个也可以用两种接口实现filter方法 或者 实现:before和:after方法
- 这个也可以用两种接口实现filter方法 或者 实现:before和:after方法
# 1:
# around_filter BenchmarkingFilter
#
# class BenchmarkingFilter
# def self.filter(controller, &block)
# Benchmark.measure(&block)
# end
# end
#
# 2:
#
# around_filter Authorizer.new
#
# class Authorizer
# # This will run before the action. Redirecting aborts the action.
# def before(controller)
# unless user.authorized?
# redirect_to(login_url)
# end
# end
#
# # This will run after the action if and only if before did not render or redirect.
# def after(controller)
# end
# end
- 1.3.3 传递inline方法
- 1.3.3 传递inline方法
# around_filter do |controller, action|
# logger.debug "before #{controller.action_name}"
# action.call
# logger.debug "after #{controller.action_name}"
# end
- 2 使用方法
- 2.1 传递filter方法名(要用Symbol)
# 这个是最常用的方法
# before_filter :audit
#
# private
# def audit
# # record the action and parameters in an audit log
# end
- 2.2 传递外部Filter类
# class OutputCompressionFilter
# def self.filter(controller)
# controller.response.body = compress(controller.response.body)
# end
# end
#
# class NewspaperController < ActionController::Base
# after_filter OutputCompressionFilter
# end
- 2.3 传递inline方法
# class WeblogController < ActionController::Base
# before_filter { |controller| head(400) if controller.params["stop_action"] }
# end
- 3 Filter的顺序
prepend_before_filter 可以将指定的方法放在所有filter方法之前
# class ShoppingController < ActionController::Base
# before_filter :verify_open_shop
# before_filter :verify_base_ready
#
# class CheckoutController < ShoppingController
# prepend_before_filter :ensure_items_in_cart, :ensure_items_in_stock
上面程序中filter顺序为
1 :ensure_items_in_cart
2 :ensure_items_in_stock
3 :verify_open_shop
4 :verify_base_ready
一般而言执行顺序就是按照before_filter设置的先后
- 4 Filter的忽略
如果基类中定义了before_filter,子类中有时候不需要调用,就可以用skip_filter忽略
# class ApplicationController < ActionController::Base
# before_filter :authenticate
# around_filter :catch_exceptions
# end
#
# class WeblogController < ApplicationController
# # Will run the :authenticate and :catch_exceptions filters.
# end
#
# class SignupController < ApplicationController
# # Skip :authenticate, run :catch_exceptions.
# skip_before_filter :authenticate
# end
#
# class ProjectsController < ApplicationController
# # Skip :catch_exceptions, run :authenticate.
# skip_filter :catch_exceptions
# end
#
# class ClientsController < ApplicationController
# # Skip :catch_exceptions and :authenticate unless action is index.
# skip_filter :catch_exceptions, :authenticate, :except => :index
# end
- 5 Filter的条件选择,可以调用 :only 和 :except 选择需要挂这个filter的方法
- 6 这几种Filter如何控制程序执行
1 simply call render or redirect to halt
2 before and around may halt the request before a controller action is run.
3 after will not be executed if the chain is halted.
3 If around returns before yielding,
after will still not be run, before and controller action will not be run.
4 If before renders or redirects,
the second half of around and will still run, after and the action will not.
5 If around fails to yield, after will not be run.
# The filter chain will look like:
#
# ...
# . /
# . #around (code before yield)
# . . /
# . . #before (actual filter code is run)
# . . . /
# . . . execute controller action
# . . . /
# . . ...
# . . /
# . #around (code after yield)
# . /
# #after (actual filter code is run, unless the around filter does not yield)