Я обновляю свое приложение Rails с 6.1 до 7.0 и сталкиваюсь с этой ошибкой времени выполнения:
Я использую драгоценный камень Authlogic, но странно то, что у меня нет файла config/initializers
для Authlogic, и я не могу найти ни одного экземпляра константы, с которой он не работает.
uninitialized constant Patches::AuthlogicPasswordPatch (NameError)
/myapproot/shared/bundle/ruby/3.3.0/gems/zeitwerk-2.6.16/lib/zeitwerk/cref.rb:91:in `const_get'
/myapproot/shared/bundle/ruby/3.3.0/gems/zeitwerk-2.6.16/lib/zeitwerk/cref.rb:91:in get
ОБНОВЛЕНИЕ: После решения вышеуказанной проблемы (решение см. в комментарии @alex ниже), следующая связанная проблема Zeitwerk:
Следующим препятствием является то, что Zeitwerk не имеет одинаковых имен классов, даже если они находятся в разных пространствах имен, что и вызывает эту ошибку:
Exception Zeitwerk::NameError in Rack application object
(expected file app/services/data_tables/base.rb to define
constant Base, but didn't)
когда я включил ведение журнала Zeitwerk и запустил приложение, я увидел это:
[email protected]: file app/services/deployment/models/base.rb is ignored because app/services/data_tables/base.rb has precedence
app/services/deployment/models/base.rb
определяется как:
module Deployment
module Models
class Base < ActiveResource::Base
...
и app/services/data_tables/base.rb
это:
module DataTables
class Base
...
это то, что у меня есть в config/application.rb:
config.autoload_paths += Dir["#{config.root}/app/services/**/"]
config.eager_load_paths << "#{Rails.root}/lib"
config.eager_load_paths << "#{Rails.root}/app/services"
Может быть, вы заходите сюда guides.rubyonrails.org/… ?
@Алекс, ты был прав. мне пришлось исправить именно тот файл, у которого также было другое имя класса, а также добавить Module Patches
вокруг класса, прежде чем эта ошибка была устранена. Есть больше ошибок, когда Zeitwerk не работает с дополнительными файлами классов. Могу ли я добавить сюда более подробную информацию или мне следует закрыть этот пост и создать новый? Не был уверен, каковы рекомендации SO для этого.
Если проблема в содержимом файла, то странно, что в 6.1 это работало, а в 7.0 не работало. Также странно, что исключением является NameError, а не Zeitwerk::NameError, если это связано с автозагрузкой.
спасибо, @Алекс. Я обновил вопрос, добавив дополнительную информацию.
@XavierNoria, я добавил больше деталей к вопросу, а также пояснил, что ошибка действительно отображается как Zeitwerk::NameError. Я думаю, что Zeitwerk был необязательным в Rails 6.1, и, вероятно, поэтому этого не произошло, пока я не обновился до Rails 7.0.
@weetch Я подозреваю, что ваше приложение может содержать подстановочные знаки в конфигурации autoload_paths
. Пожалуйста, ознакомьтесь с этим разделом инструкции по миграции guides.rubyonrails.org/… . Если вы не читали это руководство, я бы порекомендовал его.
@XavierNoria, вот что у меня есть в config/application.rb: config.autoload_paths += Dir["#{config.root}/app/services/**/"]
config.eager_load_paths << "#{Rails.root}/lib"
config.eager_load_paths << "#{Rails.root}/app/services"
это не правильно?
@weetch нет, это не так. Пожалуйста, прочтите этот раздел руководства.
Я предлагаю вам удалить все autoload_paths
и просто исправить структуру файлов. подкаталоги app
уже настроены как пути автозагрузки. Я не удивлен, что из-за этого у тебя возникают все эти проблемы.
спасибо, @XavierNoria. ты был прав. Это исправление решило все оставшиеся проблемы. Я опубликовал краткий обзор исправлений.
Добавление сводки исправлений, сделанных здесь, на случай, если это поможет другим. Спасибо @XavierNoria и @Alex за помощь.
Первоначальная причина заключалась в устаревшем файле исправления для Authlogic, названном так, как не понравилось Zeitwerk. В итоге я провел рефакторинг кода, чтобы полностью избавиться от файла, но если у вас есть файлы в lib/patches
, вам нужно будет заключить код в пространство имен Module Patches
.
Другая проблема заключалась в том, что в ряде классов Zeitwerk отказывался автоматически загружать классы с одинаковыми именами (хотя они явно находились внутри разных пространств имен/структур папок). Исправление заключалось в замене этой строки pre-rails-7.0 в config/application.rb
:
config.autoload_paths += Dir["#{config.root}/app/services/**/"]
с:
config.autoload_paths += Dir["#{config.root}/app/services"]
Это решило все проблемы конфликта имен классов.
Патчи для драгоценных камней не должны быть автоматически загружаемыми/перезагружаемыми, поскольку изменения в этих файлах обычно не оказывают никакого влияния на драгоценный камень. Идиоматический способ настроить эту настройку — указать автозагрузчику игнорировать lib/patches
(либо Rails.autoloaders.main.ignore("#{Rails.root}/lib/patches")
, либо передать patches
в список игнорирования config.autoload_lib
, если он у вас есть). Затем при загрузке требуются файлы как обычно. Кроме того, поскольку эти файлы не будут управляться автозагрузчиками, для них не требуется никаких соглашений.
у вас есть файл
patches/authlogic_password_patch.rb
где-то в путях автозагрузки, который должен определятьPatches::AuthlogicPasswordPatch