我正在使用类猴子补丁(monkey-patching)的方式对Rails引擎进行修改,大致如下:
SomeClass.class_eval do
# ...
end
第一次访问网站时(至少在开发模式下),它可以正常运作,但第二次访问时,就像我的补丁从未存在过一样。我猜想这是Rails自动重新加载引擎(安装在vendor/中),而不重新加载我的代码。这是Rails 2.3。
有什么想法可以使我的代码也被重新加载吗?
我正在使用类猴子补丁(monkey-patching)的方式对Rails引擎进行修改,大致如下:
SomeClass.class_eval do
# ...
end
第一次访问网站时(至少在开发模式下),它可以正常运作,但第二次访问时,就像我的补丁从未存在过一样。我猜想这是Rails自动重新加载引擎(安装在vendor/中),而不重新加载我的代码。这是Rails 2.3。
有什么想法可以使我的代码也被重新加载吗?
编辑:这个解决方案仅适用于Rails 3+,因为它依赖于Rails::Railtie中的一些功能。将此代码放入初始化程序中。
这个问题很旧了,但我找到了一个解决方案:
Rails.configuration.to_prepare do
SomeClass.class_eval do
# ...
end
end
这会强制Rails在开发模式下每个请求都重新加载类,但在生产环境下只加载一次。
我刚写了我的第一个猴子补丁,因此需要制定一套约定。这是我想出的:
将您的扩展放置在lib/ext/
下。(由#rubyonrails IRC房间中的资深工作mad3建议) 在我的情况下,我正在向Mail::Message
类(来自mail
gem,由ActionMailer使用)添加一个方法,所以我创建了:
/lib/ext/mail/message.rb
打开类或模块并添加您的代码:
module Mail
class Message
def to_is_phone?
!!(self.to.first =~ /^\+1\d{10}$/)
end
end
end
创建一个初始化程序以加载所有猴子补丁。当引用常量时,Rails将自动加载文件,但由于您正在向现有的类/模块添加方法而不是定义新的类/模块,因此这种方法不起作用,因此您必须手动要求所有猴子补丁。 所以我创建了:
/config/initializers/monkey_patches.rb
其中包含:
require 'ext/mail/message'
monkey_patches.rb
可以替换为Dir[Rails.root.join('lib/ext/*.rb')].each { |file| require file }
,这样所有的猴子补丁都会被加载。 - Dan KohnDir[Rails.root.join('lib/ext/**/*.rb')].each { |file| require file }
- viktor_vangel看看这个宝石如何处理“装饰”(也称为猴子补丁)引擎中的某些东西或反之亦然:
虽然不太美观,但我发现如果将这种代码放在environments.rb的底部,它总是能够保证正确的启动加载顺序。
很遗憾,无法钩入Rails 2.x的重新加载机制。
您可以将补丁放置在应用程序或lib目录中的某个位置。(lib/core_ext
可能是首选位置)。然后将该目录添加到配置文件中的autoload_paths中。
您可能还需要打开类,而不是使用class_eval。