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 и советы по обновлению здесь .