Rails 6+, автозагрузчик zeitwerk и константы с разнесением имен

Автозагрузчик Rails 6+ по умолчанию - zeitwerk, что кажется большим улучшением по сравнению с предыдущими подходами.

Однако zeitwork следует соглашению для проектов Rails, что все в app/* загружается автоматически и не требует размещения имен.

Это отлично работает для app/models/user.rb потому что вам не нужно использовать Models::User но могу просто сослаться User.

Однако я добавил свой app/services каталог и пространство имен моих служебных объектов как Services::Users::Create, который будет отображаться на app/services/users/create.rb.

Zeitwork выдает ошибки, связанные с тем, что константы моего класса не существуют, поскольку ожидает Users::Create (без Services:: префикс).

Есть ли способ настроить zeitwork так, чтобы Services::пространство имен в этих случаях? На мой взгляд, гораздо проще читать код какServices::Users::Create и знай, что ты смотришь в app/services/users/create.rb файл.

Если бы ты только что Users::Create, средний разработчик Rails, вероятно, будет искать app/models/users/create.rb файл.

Мне не нравится подход к названию Users::CreateServiceмне это кажется очень неэлегантным.

Я не могу быть единственным, кто использует подобные условности; кто-нибудь еще сталкивался с решением? Я все еще просматриваю всю документацию по zeitwerk в поисках решения, но пока не нашел его.

3 ответа

https://guides.rubyonrails.org/upgrading_ruby_on_rails.html

Некоторым проектам требуется что-то вроде app/api/base.rb для определения API::Base и добавления приложения в пути автозагрузки для выполнения этого в классическом режиме. Поскольку Rails автоматически добавляет все подкаталоги приложения к путям автозагрузки, у нас есть другая ситуация, когда есть вложенные корневые каталоги, так что установка больше не работает. Подобный принцип мы объяснили выше с опасениями.

Если вы хотите сохранить эту структуру, вам нужно удалить подкаталог из путей автозагрузки в инициализаторе:

ActiveSupport::Dependencies.autoload_paths.delete("#{Rails.root}/app/api")

Мне нужно было что-то подобное, но для integrations. Я также не хотел, чтобы класс назывался Integrations::Base но вместо того, чтобы Integration::Base.

Я создал файл config/initializers/integrations.rb со следующим:

ActiveSupport::Dependencies.autoload_paths.delete("#{Rails.root}/app/integrations")

autoloader = Rails.autoloaders.main
autoloader.push_dir(Rails.root.join("app"))
autoloader.inflector.inflect "integrations" => "Integration"

Затем создал app/integrations/base.rb с участием:

module Integration
  class Base
  end
end

Немного поздно на вечеринку здесь, но была очень похожая ситуация! Даже назвал папку одинаково "Службы"

Похоже, это помогло добавить его в путь автоматической загрузки в файле application.rb:

      config.autoload_paths += %W(#{config.root}/app/services/)

Затем в подкаталоге модуль и класс были определены следующим образом:

#services/sub_folder/base.rb

      module Services
  class SubFolder::Base
  end
end

У меня есть аналогичный ответ с более подробной информацией здесь .

Тогда более общие ресурсы Zeitwerk и советы по обновлению здесь .

Другие вопросы по тегам