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

これはテスト環境と本番環境で機能しますが、config.cache_classes = false@ NoMethodErrorproduct.variations などの ProductExtender で定義されたものを呼び出そうとすると、エラーが発生します。

言うまでもなく、すべてのテストに合格したのに、開発中にエラーが発生するのを見るのはゾッとします。を設定すると発生しませんcache_classes = trueが、やってはいけないことをしているのだろうかと思います。

私の質問は 2 つあります。なぜこれが起こっているのですか。また、別のアプリケーションのオブジェクトでメソッドを拡張/呼び出しするこの機能を達成するためのより良い方法はありますか?

皆さんありがとう!

4

2 に答える 2

4

to_prepare初期化子の代わりにブロックを使用して、この問題を解決することができました。このto_prepareブロックは、本番環境では 1 回、開発環境では各リクエストの前に実行されるため、ニーズを満たしているようです。

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 に答える