Rails 6: Zeitwerk::NameError がモジュールからクラスをロードしない
概要
このようなファイルがあります
#app/services/account/authenticate/base.rb
module Account
module Authenticate
AuthenticateError = Class.new(StandardError)
class Base < ::Account::Base
def self.call(*attrs)
raise NotImplementedError
end
end
end
end
ここで、rails c からコードを実行すると、エラーが発生します
> ::Account::Authenticate::AuthenticateError
=> NameError (uninitialized constant Account::Authenticate::AuthenticateError)
> ::Account::Authenticate.constants
=> [:Base, :ViaToken]
したがって、Rails は AuthenticateError クラスを認識しません。しかし、このフォルダーから次のようにネストされたクラスを作成すると、
=> Account::Authenticate::ViaToken
> ::Account::Authenticate.constants
=> [:Base, :AuthenticateError, :ViaToken]
認証エラー クラスが表示されません
> ::Account::Authenticate::AuthenticateError
=> Account::Authenticate::AuthenticateError
この問題の解決策は、最初から機能する別のファイルauthenticate_error.rbを作成することですが、この解決策は私にとって理想的ではありません。すべてのクラスまたはSMTHをプリロードする解決策はありますか?
(Ruby 2.6 と Rails 6.0.0.rc2)
解決策
Rails 6.0.2 アプリケーションを Ubuntu 18.04 サーバーにデプロイするときに、これと同じ問題が発生しました。
問題はツァイトヴェルクにあることがわかりました。 Zeitwerk は、Rails 6 で使用される新しいコード ローダー エンジンです。これは、古いクラシック エンジンに代わるすべての Rails 6 以降のプロジェクトの新しいデフォルトとなることを目的としています。 Zeitwerk は、コードの自動読み込み、即時読み込み、および再読み込みの機能を提供します。
私がそれを解決した方法は次のとおりです。
プロジェクトの config/application.rb ファイルに移動します。
アプリケーション モジュール内に次の行を追加して、自動読み込みのクラシック モードに切り替えます。
config.autoloader = :classic
以下に例を示します。
module MyApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.0
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.
config.autoloader = :classic
end
end
ツァイトヴェルクについて詳しくは、Rails 6 でのツァイトヴェルクについての記事をご覧ください。