当cache_classes = false时,为什么包含在Rails Engine初始化器中会出现故障?

时间:2011-05-02 00:56:12

标签: ruby-on-rails rails-engines

我有一个引擎,它在其初始化器中扩展另一个引擎类,如下所示:

module MyApp
    class Engine < ::Rails::Engine
        initializer 'extend Product' do
            AnotherApp::Product.send :include, MyApp::ProductExtender
        end
    end
end

ProductExtender模块在​​包含它时调用AnotherApp :: Product上的一些方法,例如

module ProductExtender
    def self.included( model )
        model.send :include, MethodsToCall
    end

    module MethodsToCall
        def self.included( m )
            m.has_many :variations
        end
    end
end

这适用于测试和生产环境,但是当config.cache_classes = false时,当我尝试调用ProductExtender定义的内容时,它会向我抛出NoMethodError,例如@ product.variations。

毋庸置疑,看到我的所有测试都通过,然后在开发过程中遇到错误,这是令人不寒而栗的。当我设置cache_classes = true时,它不会发生,但它让我想知道我是否正在做一些我不应该做的事情。

我的问题有两个:为什么会发生这种情况,是否有更好的方法来实现在另一个应用程序对象上扩展/调用方法的功能?

全部谢谢!

2 个答案:

答案 0 :(得分:4)

我设法使用to_prepare块而不是初始化程序来解决此问题。 to_prepare块在生产中和开发中的每个请求之前执行一次,因此似乎满足了我们的需求。

我在研究Rails::Engine时并不明显,因为它是从Rails::Railtie::Configuration继承而来的。

所以不是问题中的代码,我会:

module MyApp
    class Engine < ::Rails::Engine
        config.to_prepare do
            AnotherApp::Product.send :include, MyApp::ProductExtender
        end
    end
end

答案 1 :(得分:0)

cache_classes实际上有一个误导性的名称:没有涉及缓存。如果将此选项设置为false,则rails会显式卸载您的应用程序代码并在需要时重新加载它。这使您在开发中所做的更改无需重新启动(服务器)进程即可生效。

在您的情况下,像ProductExtender一样重新加载AnotherApp :: Product,但重新加载后初始化程序不会再次触发,因此AnotherApp :: Product不会“扩展”。

我非常了解这个问题,最终运行了我的开发环境,其中cache_classes = true并偶尔重启我的服务器。我没有那么多关于引擎/插件的开发,所以这是最简单的方法。