我正在尝试编写一个扩展InheritedResources的插件。
具体来说,我想重写一些默认助手。
我希望它在安装后“正常工作”,不对应用程序代码进行任何更改。
该功能在模块中提供,该模块需要包含在正确的位置中。问题是在哪里? :)
第一次尝试是在我的插件的init.rb中执行此操作:
InheritedResources::Base.send :include, MyModule
它在生产中工作,但在开发中失败,因为InheritedResource :: Base声明为unloadable
,因此在每个请求上重新加载其代码。所以我的模块是第一个请求,
然后它消失了。
InheritedResource :: Base被任何使用它的控制器再次“拉入”:
Class SomeController < InheritedResource::Base
但是没有代码可以“拉入”我的扩展模块,因为它除了init.rb之外没有被引用,每个请求都 重新加载
所以现在我只是手动将模块包含在需要它的每个控制器中。 我甚至无法在ApplicationController中包含它一次,因为InheritedResources继承它,因此它将覆盖任何更改。
我不是在寻找关于如何'猴子补丁'的建议。该扩展正在生产中非常好。我的问题是如何在加载InheritedResources之后准确捕捉时刻以将我的扩展插入其中:)
另一种澄清的尝试:
事件的顺序是
我需要抓住g和h之间的时间点
答案 0 :(得分:4)
环境文件中的Rails :: Configuration,config
允许在开发模式下的每个请求之前运行的调度程序上注册回调,或者在生产模式下注册一次。
config.to_prepare do
# do something here
end
问题是,我不认为你的插件在运行init.rb文件时可以访问config
。这是一种直接在调度程序中注册回调的方法。把它放在init.rb文件中。
require 'dispatcher'
::Dispatcher.to_prepare do
puts "hi there from a plugin"
end
警告:我不知道这可能有什么副作用。如果可能,尝试访问config
并以正确的方式注册回调。
答案 1 :(得分:-1)
您尝试做的通常称为“MonkeyPatch” - 通过“覆盖”方法改变一个模块或类的工作方式。
这是Rails中的常见做法,但这并不意味着它是最好的做事方式 - 如果可能的话,最好使用公共继承(它更明确地说明你所做的更改)。
关于“放置文件的位置”的问题:它通常是lib /目录。这可能意味着rails应用程序的lib,或者gem或插件中的lib目录,如果您遇到这种情况。
例如,如果要更改的文件是继承资源的lib/generators/rails/templates/controller.rb
,则首先要做的是在lib /文件夹中复制该目录结构('lib / generators / rails / templates / controller.rb')
在您的新文件中(开头为空),您可以覆盖方法。但是,您还必须具有模块/类层次结构。所以如果原始宝石有这个:
module foo
module bar
def f1
...
end
def f2
...
end
end
def f3
...
end
end
你想要修改f1,你必须尊重foo-bar模块。
module foo
module bar
def f1
... # your code here
end
end
end
现在您需要做的最后一件事是确保在正确的时间执行此代码。如果您使用的是应用程序的lib /文件夹,则需要在initializers/
文件夹和require
新文件中创建一个条目。如果您正在开发gem /插件,那么您将在该插件的“root”文件夹中有一个init.rb文件。把'需要'放在那里。
我对这个unloadable
的东西不太熟悉;也许我问了一些明显的东西 - 但你是否尝试过让你的扩展模块无法加载? (如果您对模块进行了monkeypatched而不是创建新模块,则不应该需要这样做)