Лучший подход для маркировки конкретных моделей Rails для использования в модуле - PullRequest
0 голосов
/ 25 декабря 2018

Я пытаюсь написать плагин / расширение lib, чтобы выполнить действие, в котором мне нужно знать, какие модели были помечены для использования с этим плагином.

В настоящее время я отмечаю модели в соответствии сacts_as_something метод, который добавляется к каждой модели, предназначенной для использования с плагином.

Основной файл плагина выглядит следующим образом:

# 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

Предполагается использовать для вызоваконтроллер Foo.perform, который должен знать помеченные модели, чтобы выполнить запланированное действие, идея состоит в том, чтобы получить список моделей от Foo.models.

. Он работает, как предполагалось, если config.eager_loadв development.rb установлено значение true, в противном случае файлы моделей еще не использовались / не загружались, и поэтому Foo.models является пустым массивом.

Моя цель - иметь возможность добавлять больше моделей в Fooбез необходимости изменять код Foo следующим образом.

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

Есть идеи, как лучше всего это реализовать?

1 Ответ

0 голосов
/ 25 декабря 2018

У меня раньше была похожая проблема в моем геме .

Я закончил загрузкой ТОЛЬКО файлов модели (что является минимумом моего требования, таким же, как у вас, потому чтокод DSL там, как ваш acts_as_foo), и не требует немедленной загрузки всех файлов, связанных с 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
...