下面的代码显示了两个按不同顺序添加了before_filters的控制器。因此,控制器具有不同的行为。
当current_user为nil(已注销)时:
- FooController->重定向到login_path
- BarController->重定向到root_path
当然,你可以将这两种方法结合起来,使它们更智能,使这个特定的例子消失——但这没有抓住这个问题的重点。
当前的问题是,在ActionController中,添加过滤器的顺序是相关的。(你也可以说这个实现不是最好的,但它就是这样——所以让我们继续前进)
既然ActionController就是这样工作的,我想测试一下这种行为。然而,没有必要在每个单独的操作上测试前置过滤器的结果(而不是DRY)。据我所知,真正重要的是每个操作上过滤器链的结果顺序。
before_filter :require_user
实际做的唯一一件事就是将一个项注入回调链中——这就是我在子类中应该测试的全部内容——即已经向链中添加了一个附加项。我不需要测试require_user
对我的操作的影响——它们可以而且应该被清除。
话虽如此,但钱的问题是:是否有一个公共的API可以返回给定控制器和操作的过滤器链中的方法?这应该包括过滤器之前、之后和周围的适当顺序。
class ApplicationController < ActionController::Base
def require_user
unless current_user
redirect_to login_path and return
end
end
def require_admin
unless current_user.try(:admin?)
redirect_to root_path and return
end
end
end
class FooController < ApplicationController
before_filter :require_user
before_filter :require_admin
end
class BarController < ApplicationController
# reverse the order of the filters
before_filter :require_admin
before_filter :require_user
end
您可以通过_process_action_callbacks类方法访问筛选器列表。对于过滤器列表,您可以:
FooController._process_action_callbacks.collect &:filter