Подтвердить что ты не робот

Модели Rails усиливают нагрузку

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

Например, у меня есть следующий класс:

# app/models/foo_class.rb
class FooClass < MySpecialBaseClass
  # pasta code
end

Он не будет найден с помощью:

irb> ObjectSpace.each_object.select { |obj| obj.is_a?(Class) && obj <= MySpecialBaseClass }
=> []

Пока я не назову const:

irb> FooClass

Затем возвращается:

irb> ObjectSpace.each_object.select { |obj| obj.is_a?(Class) && obj <= MySpecialBaseClass } 

=> [FooClass]

Как мне это сделать?

4b9b3361

Ответ 1

После большого количества проб и ошибок я недавно узнал, что ответ Джейсона Вальдрипа несколько неполный. Начиная с Rails 5, Rails.application.eager_load! действительно загрузит все каталоги, указанные в config/application.rb. Но это не соответствует фактическому поведению Rails в производстве. Для этого нужно вместо этого зеркально отразить то, что делает Rails:

Rails.configuration.eager_load_namespaces.each(&:eager_load!)

Существенная разница между подходами заключается в том, что ответ OPs не будет загружать файлы в каталогах приложений Engine которые живут в папках с gems или vendor. Принимая во внимание, что Rails сам определяет, где существуют подклассы Engine и будет следить за тем, чтобы соответствующие подкаталоги app загружались с нетерпением.

За кулисами

Rails 5 добавляет загружаемые каталоги в railties-5.0.2/lib/rails/engine/configuration.rb:39, где он запускается

      paths.add "app",                 eager_load: true, glob: "{*,*/concerns}"
      paths.add "app/assets",          glob: "*"
      paths.add "app/controllers",     eager_load: true
      paths.add "app/channels",        eager_load: true, glob: "**/*_channel.rb"
      paths.add "app/helpers",         eager_load: true
      paths.add "app/models",          eager_load: true
      paths.add "app/mailers",         eager_load: true

Эти каталоги в настоящее время не включены в Rails.application.eager_load! умолчанию Rails.application.eager_load!

Ответ 2

Ну, после некоторого копания, на самом деле это действительно просто. Просто нужно запустить следующее.

Rails.application.eager_load!

Ответ 3

Из Настройка Rails-приложений

  1. config.eager_load при true Eager загружает все зарегистрированные config.eager_load_namespaces. Это включает в себя ваше приложение, движки, фреймворки Rails и любое другое зарегистрированное пространство имен.
  2. config.eager_load_namespaces регистрирует пространства имен, которые стремятся загружается, когда config.eager_load имеет значение true. Все пространства имен в списке должен ответить на eager_load! Метод.
  3. config.eager_load_paths принимает массив путей, с которых Rails будет загружаться при загрузке, если включены классы кэша. По умолчанию каждая папка в каталоге приложения.

EDIT:

Для ручной загрузки вы должны сделать что-то вроде:

matcher = /\A#{Regexp.escape(load_path)}\/(.*)\.rb\Z/
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
  require_dependency file.sub(matcher, '\1')
end

Ответ 4

With Rails 6, Zetiwerk стал загрузчиком кода по умолчанию.

Попробуйте это для быстрой загрузки:

Zeitwerk::Loader.eager_load_all