6

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

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

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

不用说,看到我所有的测试都通过了,然后又因为开发中的错误而受到猛烈抨击,这令人不寒而栗。当我设置时它不会发生cache_classes = true,但这让我想知道我是否在做我不应该做的事情。

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

谢谢大家!

4

2 回答 2

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
于 2011-05-02T17:15:03.630 回答
0

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

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

我非常了解这个问题,最终使用 cache_classes = true 运行我的开发环境,并偶尔重新启动我的服务器。我对引擎/插件没有太多的开发工作,所以这是最简单的方法。

于 2011-05-02T11:24:45.310 回答