我有一个我想根据我正在运行的rails环境覆盖的库模块
模块位于lib / package / my_module.rb:
module Package
module MyModule
puts "Defining original module"
def foo
puts "This is the original foo"
end
end
end
我已经能够部分解决Overriding a module method from a gem in Rails的信息 - 特别是在我的环境/ dev_stub.rb中:
Package::MyModule.module_eval do
puts "Defining override"
def foo
puts "This is foo override"
end
end
(当rails尝试查找与包相关的其他类时,该链接的其他解决方案似乎会导致错误)
现在,这似乎让我大部分都在那里,如果我设置
,它就会起作用config.cache_classes = true
...但是我想将它用作存根开发环境,对于dev环境的这个值的注释建议是使用false ...在这种情况下,覆盖仅在第一次包含模块时起作用以及随后的任何时候,它都使用原始版本。
我的问题:我是否以正确的方式解决这个问题?我可以修改lib模块本身以基于RAILS_ENV有条件地覆盖,但我想保持它比那更清洁......
修改
我的用例是从控制器功能引用它。如果我有
class SomethingController < ApplicationController
def show
Package::MyModule.foo
end
end
和config.cache_classes=false
(我理想情况下,因为它是一个开发环境),并通过我的网络浏览器(http://localhost/something/show
)访问该操作,然后在我第一次点击它时,我的覆盖被加载并且它可以工作,但是第二次以及随后的任何时候,重新加载原始库类(在我的控制台上输出“定义原始模块”而没有“定义覆盖”),并且覆盖丢失。
我尝试的另一个替代方法是向environment.rb添加类似config.load_paths += %W( #{RAILS_ROOT}/lib_patch/#{RAILS_ENV})
的内容 - 但是如果没有在原始库中放入显式挂钩以基本上加载补丁,则定义相同的模块/类并不是很有效存在
编辑2(响应@apneadiving答案)
我试过没有module_eval这样做,只是在development_stub.rb中使用以下内容:
require 'package/my_module'
module Package
module MyModule
puts "Defining override"
def foo
puts "This is foo override"
end
end
end
我最初遇到的问题是Rails不再自动查找我的lib目录中的所有内容,我需要在所有其他lib文件(以及引用libs的控制器)中覆盖'require'语句来覆盖他们所有的依赖。虽然这一切都已完成,但它确实有效,但它也具有与config.cache_classes=true
类似的效果,因为即使在没有猴子的常规开发环境中,所有的lib类也不会在更改时重新加载 - 补丁(因为添加了所有'require'语句)。
答案 0 :(得分:1)
在dev_stub.rb中设置config.cache_classes=true
并使用module_eval
定义问题中描述的补丁似乎是实现目标的方法 - 为模块创建特定于环境的补丁这不会影响代码路径和Rails类加载行为中的其他环境。
答案 1 :(得分:0)
你可以简单地覆盖模块,而不是module_eval
的实例。
我猜你的模块是作为Mixin包含的,它的方法不会受到你的猴子补丁的影响。
这就是alias_method_chain
开始行动的地方。
请查看this great article,了解如何使用它来满足您的需求。