有一个宝石,追加 before_filter
到Rails应用:
class Railtie < Rails::Railtie
initializer "..." do
ActiveSupport.on_load(:action_controller) do
ActionController::Base.send(:include, Filter)
...
module Filter
extend ActiveSupport::Concern
included do
append_before_filter :set_locale
end
def set_locale
....
这是应用程序中的一些控制器:
class DesktopsController < ApplicationController
before_filter :set_language_in_session
现在问题是来自gem的before_filter
被放入DesktopsController的before_filter
之前的过滤器链中:
DesktopsController._process_action_callbacks.select { |c| c.kind == :before }.collect { |filter| filter.filter }
=> [
[0] :set_locale,
[1] :set_language_in_session
]
如何将gem中的before_filter
( set_locale )置于所有其他过滤器之后?秘密可能在于这一行:
ActiveSupport.on_load(:action_controller) do
但我尝试过不同的图书馆而没有任何运气......
顺便说一下。这是宝石的full code。 Ruby 1.9.2,Rails 3.0.5。
答案 0 :(得分:3)
改编宝石永远不会奏效。 gem被初始化为rails过程中的第一件事,因此在任何实际的控制器启动之前。所以这意味着,无论你做什么,很可能来自宝石的过滤器仍然是第一个宝石。
所以我看到的唯一解决方案是:
prepend_before_filter
执行set_locale
之前需要执行的操作。skip_before_filter
和明确的before_filter
。在rails 2应用程序中,我们设计了一个hack来确保某些过滤器作为最后一个过滤器运行,通过覆盖perform_action_without_filters
(请参阅Is there a way to force a before_filter to always execute last?)但我们在升级到rails 3时将其删除了
答案 1 :(得分:2)
我的回答是基于nickgrim的answer,我也发现它非常聪明。传递给included
的块在包含模块时会触发类(class_eval
)。您可以通过在set_locale_filter
块(以及其他方式)中定义类方法来使included
成为类方法。
module Filter
extend ActiveSupport::Concern
included do
append_before_filter :set_locale_filter
def self.set_locale_filter
append_before_filter :set_locale
end
end
def set_locale
#
end
end
有人,如果我弄错了,请纠正我。现在已经很晚了:))
答案 2 :(得分:0)
试试这个:
class DesktopsController < ApplicationController
skip_before_filter :set_locale
before_filter :set_language_in_session
before_filter :set_locale
end
<强>参考强>
答案 3 :(得分:0)
我还没有尝试过,但你可以查看prepend_before_filter,它声称将提供的过滤器提升到列表的顶部(最终在:set_locale之前)。
class DesktopsController < ApplicationController
prepend_before_filter :set_language_in_session
end
文档:http://apidock.com/rails/ActionController/Filters/ClassMethods/prepend_before_filter
要尝试的另一件事是使用around_filter:set_language_in_session(即使你在动作后没有做任何事情)。过滤器在before_filters之前发生,因此它可能是强制它首先发生的好方法。
答案 4 :(得分:0)
gem本身位于Github上,因此您可以对其进行分叉并更改代码,然后让代码拉出您的版本的gem。这是一个选择吗?如果是这样,您可以在gem中注释before_filer
,并在ApplicationController
中自行调用:
module Filter
extend ActiveSupport::Concern
included do
# append_before_filter :set_locale
end
def set_locale
....
现在只需在所有其他过滤器之后自行调用:
class ApplicationController < ActionController::Base
before_filter :do_this, :do_that, :set_locale
...
end
你想什么?
答案 5 :(得分:-1)
根本没试过,但是:你能拥有宝石before_filter
运行append_before_filter
吗?类似的东西:
module Filter
...
included do
append_before_filter :append_set_locale_filter
end
def append_set_locale_filter
append_before_filter :set_locale
end
def set_locale
...
end
...
end
答案 6 :(得分:-1)
就个人而言,我可能会编写一段中间件来执行您的操作,因为这样您就不必担心过滤器发生的顺序。