Techioz Blog

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 でのツァイトヴェルクについての記事をご覧ください。