Rails 引擎不缓存

发布于 2024-10-21 01:24:20 字数 1575 浏览 1 评论 0原文

在开发过程中,我尝试通过在 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 方法都会被调用,并依次在我的全局模型数组中一遍又一遍地附加相同的模型。

正如您在下面看到的,每当我循环遍历所有模型时,它都会继续附加自身。

在此处输入图像描述

有什么方法可以在我的引擎中缓存某些类吗?或者我使用模型本身内的钩子注册模型的方法是否存在缺陷?

In development I am trying to gather all models within my app by including a method within ActiveRecord::Base classes so they can configure the models and it will give me a hook to add that model to a global array.

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

My EngineName::Models class is just a wrapper that holds all 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

On each refresh though, the config_block method within my model gets called and in turn appends the same model over and over within my global array of models.

As you can see down below, whenever I loop through all my models, it will keep on appending itself.

enter image description here

Is there any way to cache certain classes within my engine? Or is there a flaw within my approach of registering models with a hook within the model itself?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

装迷糊 2024-10-28 01:24:20

问题是,在您的开发环境中,您的模型会根据每个请求重新加载,以便对这些类的更改生效,并且您不必在每次更改源代码时重新启动服务器。您可以在控制台中看到此行为:

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 即可。

The issue is that in your development environment your models get reloaded on every request so that changes to these classes take effect and you don't have to re-boot your server every time you make a change to your source code. You can see this behavior in the console:

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

What this means is that when you call @models.include?(klass) you are actually checking your current instantiation of that object against one from a previous request. What you'll notice is that over time your memory gets bloated because these objects will not be deleted - since garbage collection will keep them around because of the reference to them in your @models instance variable. This won't be a problem in production, because classes are only loaded once, but it will cause you problems in development.

To get around this I would recommend doing something like this:

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

Using a hash will let you keep track of models by their names, and whenever a new version of a model comes around it will replace the old out-dated version. This should help in your development environment. To get a list of all the models you'll simply use @models.values and to get a list of the model names you'll simply use @models.keys.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文