1

開発中は、クラス内にメソッドを含めてアプリ内のすべてのモデルを収集しActiveRecord::Base、モデルを構成できるようにします。これにより、そのモデルをグローバル配列に追加するためのフックが得られます。

module EngineName
  module ActiveRecordExtensions
    extend ActiveSupport::Concern

    included do
      def self.inherited(klass) #:nodoc:
        klass.class_eval do
          def self.config_block(&block)
            abstract_model = EngineName::AbstractModel.new(self)
            abstract_model.instance_eval(&block) if block

            EngineName::Models.add(abstract_model)
          end
        end
      end
    end
  end
end

EngineName::Modelsのクラスは、すべてのモデルを保持する単なるラッパーです。

module EngineName
  class Models
    class << self
      def all
        @models ||= []
      end
      alias_method :models, :all

      def navigation
        @models - excluded_navigation_models
      end

      def routed
        @models - excluded_route_models
      end

      # Creates an array of models if none exists. Appends new models
      # if the instance variable already exists.
      def register(klass)
        if @models.nil?
          @models = [klass]
        else
          @models << klass unless @models.include?(klass) || excluded_models.include?(klass)
        end
      end
      alias_method :add, :register
    end
  end
end

ただし、更新するたびconfig_blockに、モデル内のメソッドが呼び出され、モデルのグローバル配列内に同じモデルが何度も追加されます。

以下に示すように、すべてのモデルをループするたびに、それ自体が追加され続けます。

ここに画像の説明を入力してください

エンジン内に特定のクラスをキャッシュする方法はありますか?または、モデル自体のフックにモデルを登録するという私のアプローチに欠陥がありますか?

4

1 に答える 1

2

問題は、開発環境では、リクエストごとにモデルがリロードされるため、これらのクラスへの変更が有効になり、ソースコードに変更を加えるたびにサーバーを再起動する必要がないことです。この動作はコンソールで確認できます。

User.object_id
=> 2203143360
reload!
=> true
User.object_id
=> 2212653160

これが意味するのは、呼び出すときに@models.include?(klass)、そのオブジェクトの現在のインスタンス化を前のリクエストのインスタンス化と実際に照合しているということです。これらのオブジェクトは削除されないため、時間の経過とともにメモリが肥大化することに気付くでしょう。これは、@ modelsインスタンス変数でオブジェクトが参照されているため、ガベージコレクションによってオブジェクトが保持されるためです。クラスは1回しかロードされないため、これは本番環境では問題になりませんが、開発では問題が発生します。

これを回避するには、次のようなことをお勧めします。

module EngineName
  class Models
    class << self
      def all
        @models ||= {}
      end
      alias_method :models, :all

      def register(klass)
        if @models.nil?
          @models = {klass.name => klass}
        else
          @models[klass.name] = klass unless excluded_models.keys.include?(klass.name)
        end
      end
      alias_method :add, :register
    end
  end
end

ハッシュを使用すると、モデルを名前で追跡できます。モデルの新しいバージョンが登場すると、古いバージョンが置き換えられます。これは、開発環境で役立つはずです。使用するすべてのモデルのリストを取得するには、単純に使用@models.valuesするモデル名のリストを取得します@models.keys

于 2011-03-08T18:58:40.840 に答える