如何在rails插件中正确扩展ActionController

时间:2009-09-07 00:39:03

标签: ruby-on-rails

我正在编写一个Rails插件(让我们称之为Foo)。 我希望它在控制器中提供“bar”功能,以便我可以这样做:

class ApplicationController
  bar ...
end

bar是通过插件加载文件vendor / plugins / foo / init.rb定义的。像

这样的东西
class ActionController::Base
  def self.bar
    ...
  end
end

问题是其他一些插件(在我的情况下是ResourceController)可能会在 foo之前加载并访问ApplicationController。

所以会发生的事情是,在插件'foo'之前加载了ApplicationController并且因为没有'bar'定义 YET 而失败。

那么......我如何正确使其有效?

我注意到许多其他扩展ActionController的插件(例如inherited_resources,resource_controller)正在做同样的事情,所以看起来是谁首先加载以决定它是否失败或工作。

我知道我可以将代码放在某个模块中,并在调用'foo'之前手动将模块添加到ApplicationController代码中。我不愿意,我喜欢'foo'的清洁。

我也不想做手册'要求'。插件本身应该自动加载:)

2 个答案:

答案 0 :(得分:1)

您拥有的是经典的插件加载顺序问题。 Ryan Daigle在2007年就有了nice article。我将在这里总结一下这个建议:

# in RAILS_ROOT/config/environment.rb:
...
Rails::Initializer.run do |config|
  # load Bar before Foo, then everything else:
  config.plugins = [ :bar, :foo, :all ]
  ...
end

答案 1 :(得分:0)

据我了解,

ResourceController在插件foo之前加载,并尝试使用您在bar中定义的foo方法。 通常,在应用程序类之前加载gem和plugins。 (看看rails/railties/lib/initializer.rb)。你能提供一个错误的堆栈跟踪,以便可以调试它。

另外,对于扩展课程,这似乎是一个更好的选择:

module ActionController
  class Base
     class << self
       ... # Class methods here
     end
  ... # Instance methods here
  end
end