简体   繁体   English

标记要在模块中使用的特定 Rails 模型的最佳方法

[英]Best approach to mark specific Rails Models to be used in a module

I am trying to write a lib plugin/extension to perform an action where I need to know which Models have been marked for use with this plugin.我正在尝试编写一个 lib 插件/扩展来执行一个操作,我需要知道哪些模型已被标记为与此插件一起使用。

Currently, I am marking the models in the fashion of acts_as_something method which is added to each Model intended to be used with the plugin.目前,我正在以acts_as_something方法的方式标记模型,该方法被添加到每个打算与插件一起使用的模型中。

The main file of the plugin looks like this插件的主文件如下所示

# lib/foo.rb
module Foo
  class << self
    attr_accessor :models
  end
  self.models = []

  module Model
    def acts_as_foo
      Foo.models << self
    end
end

ActiveSupport.on_load(:active_record) do
  extend Foo::Model
end

The intended use is to then call in a controller Foo.perform , which needs to know the marked models in order to carry out the intended action, the idea being getting the list of models from Foo.models .预期用途是然后调用控制器Foo.perform ,它需要知道标记的模型才能执行预期的操作,其想法是从Foo.models获取模型列表。

It works as intended if when config.eager_load is set to true in development.rb , otherwise the files of the models have not been used/loaded yet and therefore Foo.models is an empty Array.如果在development.rb中将config.eager_load设置为 true ,它会按预期工作,否则模型的文件尚未使用/加载,因此Foo.models是一个空数组。

My goal is to be able to add more models to Foo without having to change Foo's code like this.我的目标是能够向 Foo 添加更多模型,而无需像这样更改 Foo 的代码。

#app/models/bar.rb
class Bar < ApplicationRecord
  acts_as_foo
end

Any ideas on the best way to implement this?关于实现这一点的最佳方法的任何想法?

I had a similar problem before in my gem .之前在我的 gem 中遇到过类似的问题

I ended up loading ONLY model files (which is the minimum of my requirement same as yours because the DSL code is there like your acts_as_foo ), and not immediately eager loading all Rails-related files using Rails.application.eager_load!我最终加载模型文件(这是我的最低要求,因为 DSL 代码就像你的acts_as_foo ),并没有立即使用Rails.application.eager_load!加载所有与 Rails 相关的文件Rails.application.eager_load! . .

# lib/foo.rb
module Foo
  class << self
    attr_accessor :models
  end

  self.models = []

  class Engine < Rails::Engine
    initializer 'foo.eager_load_models' do |app|
      unless app.config.eager_load
        models_load_path = File.join(Rails.root, 'app', 'models')

        # copied from https://apidock.com/rails/Rails/Engine/eager_load%21/class
        matcher = /\A#{Regexp.escape(models_load_path.to_s)}\/(.*)\.rb\Z/
        Dir.glob("#{models_load_path}/**/*.rb").sort.each do |file|
          app.require_dependency file.sub(matcher, '\1')
        end
      end
    end
  end

  module Model
    def acts_as_foo
      Foo.models << self
    end
  end
end

ActiveSupport.on_load(:active_record) do
  extend Foo::Model
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM