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 实例变量中引用它们而保留它们。这在生产中不会成为问题,因为类只加载一次,但它会导致您在开发中出现问题。

为了解决这个问题,我建议做这样的事情:

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 回答