覆盖特定rails环境的lib模块方法

时间:2011-07-29 19:00:16

标签: ruby-on-rails ruby

我有一个我想根据我正在运行的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'语句)。

2 个答案:

答案 0 :(得分:1)

在dev_stub.rb中设置config.cache_classes=true并使用module_eval定义问题中描述的补丁似乎是实现目标的方法 - 为模块创建特定于环境的补丁这不会影响代码路径和Rails类加载行为中的其他环境。

答案 1 :(得分:0)

你可以简单地覆盖模块,而不是module_eval的实例。

我猜你的模块是作为Mixin包含的,它的方法不会受到你的猴子补丁的影响。

这就是alias_method_chain开始行动的地方。

请查看this great article,了解如何使用它来满足您的需求。