所以我有一个 Rails 3.0 引擎(gem)。
它在 app/controllers/advanced_controller.rb 中提供了一个控制器,在 app/helpers/advanced_helper.rb 中提供了一个相应的助手。(当然还有一些观点)。
到目前为止一切顺利,控制器/帮助程序/视图只是在使用 gem 的应用程序中自动可用,太好了。
但我想让本地应用程序选择性地覆盖引擎中 AdvancedHelper 的辅助方法(理想情况下能够调用“超级”)。这是一件非常合理的事情,想要允许,对,一个完全合理的(我认为很常见的)设计?
问题是,我似乎找不到任何方法让它工作。如果应用程序定义了它自己的 app/helpers/advanced_helper.rb (AdvancedHelper),那么引擎中的那个永远不会被加载——所以如果你想替换那里的所有辅助方法(不调用 super),这将起作用,但如果你只是想超越一个。
所以这实际上是有道理的,所以我选择了一个不同的名字。让我们称我的本地人为 ./app/helpers/local_advanced_helper.rb (LocalAdvancedHelper)。这个助手确实被加载了,如果我把一个不在原始引擎的 AdvancedHelper 中的方法放在那里,它就可以用于视图。
但是,如果我在其中放置一个与引擎的 AdvancedHelper 中的方法同名的方法......我的本地方法永远不会被调用。就像 AdvancedHelper(来自引擎)在调用链中比 LocalAdvancedHelper(来自应用程序)更早。事实上,如果我打开调试器并查看 helpers.ancestors,这正是正在发生的事情,它们与我在祖先链中的顺序相反。因此,AdvancedHelper(来自引擎)理论上可以调用“super”来调用 LocalAdvancedHelper(来自应用程序)——但这当然没有多大意义,你永远不想这样做。
但我想做的……我做不到。
任何人都有任何想法,有没有办法提供这种设计,这对我来说似乎完全合理,应用程序可以选择性地覆盖引擎中的辅助方法?
任何人都对它为什么会这样工作有任何解释吗?我尝试查看实际的 Rails 源代码,但很快就迷路了,围绕这些东西的代码非常抽象地分散在一堆地方。
这是一个非常深奥的问题,我很悲观,任何人都会有任何想法,希望你能给我惊喜!
== 更新
好的,为了了解 Rails 代码的哪一部分在哪里被调用,我在每个助手上放置了一个“def self.included ; debugger ; end”,然后在调试器中我可以引发异常以查看堆栈跟踪。
那仍然没有真正帮助我深入了解它,Rails 代码到处乱跳,非常混乱。
但是很明显,与其他助手相比,不同的rails代码调用了具有“标准”名称的助手(即WidgetHelper),以包含在给定控制器的“主”视图助手模块中。我想知道我是否给助手一个不同的名称,然后使用(“helper OtherNamedAdvancedHelper”)手动将它包含在我的控制器中,如果这会改变加载顺序。