【完全版】Ruby/Rails「NameError: uninitialized constant」エラーの原因と対処法|Zeitwerk時代の定数解決
- 作成日 2026.06.26
- rails
Ruby on Rails 開発で頻発するエラー:
NameError (uninitialized constant User)
NameError (uninitialized constant Api::V1::UsersController)
Zeitwerk::NameError (expected file app/models/vat.rb to define constant Vat, but didn't)
NameError: uninitialized constant in an initializer
NameError: uninitialized constant は「Rubyが指定された定数を見つけられない」エラー。Rails 6から標準採用された Zeitwerk autoloader の規約に従っていない場合、シビアに発生します。
- ファイル名・クラス名の対応が分からない
- ネストしたモジュールで急に発生
- VAT、CSV、JSON 等の頭字語クラスで頻発
- 本番でだけ発生する(development では動く)
- gem内のクラスを参照したら出る
- Rails アップグレード後に大量発生
requireで対処すべきか、autoload に任せるべきか
など、初学者から中級者まで悩まされ続けます。
本記事では、NameError: uninitialized constant のすべての原因と対処法を、Zeitwerk 時代の実践的なリファレンスとして整理します。エラーの本質、Zeitwerk の規約、ファイル命名規則、acronym対応、autoload_paths、zeitwerk:check、lib/ の扱い、Classic Autoloader からの移行、Gem との競合、関連エラー、FAQまで完全網羅。この1本で uninitialized constant エラーを完全攻略できます。
- 1. 結論:今すぐ試すべき3ステップ
- 2. まず押さえる:定数とは何か
- 3. Zeitwerk: Rails 7+ のautoloader
- 4. 発生原因と対処パターン
- 5. zeitwerk:check の活用
- 6. Classic Autoloader からの移行
- 7. 開発環境 vs 本番環境
- 8. Gem 開発時の Zeitwerk 統合
- 9. ActiveSupport::Autoload との違い
- 10. トラブルシューティング
- 11. よくある質問(FAQ)
- 11.1. Q1. Rails 7/8 でも require は必要ですか?
- 11.2. Q2. lib/ ディレクトリのファイルを使いたい
- 11.3. Q3. acronym 設定の確認方法
- 11.4. Q4. クラスを再ロード(reload)する方法
- 11.5. Q5. constantize で NameError
- 11.6. Q6. 名前空間モジュールを別ファイルにすべき?
- 11.7. Q7. テンプレートで NameError
- 11.8. Q8. テストで NameError
- 11.9. Q9. 環境別の挙動
- 11.10. Q10. ActiveSupport::Autoload は使うべきか?
- 11.11. Q11. Engine gem との競合
- 11.12. Q12. Zeitwerk のドキュメントは?
- 12. 関連エラーとの違い
- 13. 参考リンク・関連資料
- 14. まとめ
結論:今すぐ試すべき3ステップ
時間がない方向けに、まず実施すべき手順を示します。
ステップ1:エラーから定数名を取得
NameError (uninitialized constant Api::V1::UsersController)
↑
ロードできなかった定数
ステップ2:ファイル配置を確認
Api::V1::UsersController なら:
app/controllers/api/v1/users_controller.rb
↑ ↑
api/ v1/
ディレクトリ名と名前空間(モジュール)が完全一致している必要があります。
ステップ3:規約に従って修正
# app/controllers/api/v1/users_controller.rb
module Api
module V1
class UsersController < ApplicationController
# ...
end
end
end
それでも解決しない場合:
# Zeitwerk チェック
bin/rails zeitwerk:check
詳細は以下で解説します。
まず押さえる:定数とは何か
Ruby の定数
Ruby では大文字で始まる識別子はすべて定数。クラス・モジュールも定数の一種:
PI = 3.14 # 定数
class User end # User も定数(Class オブジェクトを格納)
module Api end # Api も定数(Module オブジェクト)
NameError: uninitialized constant とは
「そのスコープから参照可能な場所に、その名前の定数が定義されていない」エラー:
puts User
# => NameError (uninitialized constant User)
Ruby の定数探索ルール
Rubyは以下の順序で定数を探します:
- 現在のクラス・モジュール
- そのスーパークラス
- トップレベル(Object)
class Foo
BAR = 100
def value
BAR # 1. Fooクラス内で見つかる
end
end
ネストしたモジュールでは:
module Outer
module Inner
CONST = 1
end
end
# 1. Outer::Inner にアクセス → 内側から参照
module Outer
module Inner
puts CONST # 1(同じスコープ)
end
end
# 2. 外から参照
puts Outer::Inner::CONST # 1(完全修飾)
# 3. 失敗例
puts Inner::CONST
# => NameError (uninitialized constant Inner)
Zeitwerk: Rails 7+ のautoloader
Zeitwerk とは
Rails 6で導入され、Rails 7以降でデフォルトの新しい自動ロード機構。これにより require を書かなくても、定数参照時にファイルが自動的にロードされます。
# どこかでこれを書くだけで自動でロード
user = User.new # app/models/user.rb が自動ロード
Zeitwerk の基本規約
ファイル名 = スネークケース、クラス名 = キャメルケース:
| ファイルパス | 期待される定数 |
|---|---|
app/models/user.rb | User |
app/models/users_helper.rb | UsersHelper |
app/controllers/users_controller.rb | UsersController |
app/controllers/api/v1/users_controller.rb | Api::V1::UsersController |
app/services/payment_processor.rb | PaymentProcessor |
ディレクトリ階層 = モジュール階層:
app/models/
├── user.rb # User
├── api/
│ ├── client.rb # Api::Client
│ └── v1/
│ └── request.rb # Api::V1::Request
# app/models/api/v1/request.rb
module Api
module V1
class Request
# ...
end
end
end
autoload_paths
Zeitwerk が自動ロード対象とするディレクトリ:
# 標準の autoload_paths(Rails 7+)
- app/assets
- app/controllers
- app/controllers/concerns
- app/helpers
- app/jobs
- app/mailers
- app/models
- app/models/concerns
- app/views
確認:
Rails.application.config.autoload_paths
# または
Rails.autoloaders.main.dirs
eager_load_paths
本番環境(production)では、起動時にすべてのファイルがロードされます:
# config/environments/production.rb
config.eager_load = true
これにより:
- 起動時に一括チェック(タイポ等が早期発見)
- リクエスト処理時のロード遅延なし
- メモリ使用量は増える
発生原因と対処パターン
原因1:ファイル名とクラス名の不一致
# app/models/user.rb
class Users # ← ❌ ファイル名 user.rb なら User
end
実行:
User
# => NameError (uninitialized constant User)
対処: ファイル名と完全一致させる:
# app/models/user.rb
class User # ✅
end
または:
# app/models/users.rb(ファイル名を変える)
class Users
end
原因2:名前空間(モジュール)が不一致
# app/models/api/v1/user.rb
class User # ❌ Api::V1::User と期待される
end
エラー:
expected file app/models/api/v1/user.rb to define constant Api::V1::User, but didn't
対処:
# app/models/api/v1/user.rb
module Api
module V1
class User
# ...
end
end
end
原因3:頭字語(acronym)の問題
「VAT」「CSV」「JSON」「HTML」「API」「URL」「PDF」のような頭字語は注意。
# app/models/csv_importer.rb
class CSVImporter # ❌ Zeitwerk は CsvImporter を期待
end
エラー:
expected file app/models/csv_importer.rb to define constant CsvImporter, but didn't
対処1: acronym設定
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym "CSV"
inflect.acronym "JSON"
inflect.acronym "HTML"
inflect.acronym "API"
inflect.acronym "URL"
inflect.acronym "PDF"
inflect.acronym "VAT"
end
設定後、csv_importer.rb は CSVImporter として解決されます。
対処2: ファイル名を変える
app/models/csv_importer.rb # ❌ CSVImporter を期待するなら acronym 設定必要
↓
app/models/csv_importer.rb # ✅ Zeitwerk default なら CsvImporter で OK
原因4:複数定数の同一ファイル定義
Zeitwerk は 1ファイル1定数が原則:
# app/models/admin.rb
module Admin
class User # ❌ Admin::User を別ファイルで期待
end
class Article
end
end
対処: 名前空間モジュールとクラスを別ファイルに:
# app/models/admin.rb
module Admin
end
# app/models/admin/user.rb
module Admin
class User
end
end
# app/models/admin/article.rb
module Admin
class Article
end
end
原因5:autoload_paths 外のディレクトリ
lib/ ディレクトリは標準では autoload 対象外:
# lib/services/payment.rb
class Payment
end
# 別の場所で
Payment.new
# => NameError
対処1: autoload_paths に追加
# config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.eager_load_paths += %W(#{config.root}/lib)
対処2: app/ 配下に移動
mv lib/services app/services
Rails 7+ では lib/ を自動的に autoload しない設計。app/ 内のサービスやリブラリは app/services 等に置くのが推奨。
原因6:require_dependency の名残
Rails 6以前で require_dependency を使っていた箇所:
require_dependency 'some_file' # 非推奨(Zeitwerkでは不要)
対処: 削除する。Zeitwerk が自動的に解決します。
原因7:spring の影響(古いRails)
Rails 7.1+ では Spring が廃止されたため、現在この問題はほぼなし。古いRailsで:
bin/spring stop
でクラスキャッシュを破棄。
原因8:Gem の autoload 競合
Gemのクラスを直接参照しようとして失敗:
Stripe::Customer.create(...)
# => NameError (uninitialized constant Stripe)
対処: Gemfile に追加し、bundle install:
# Gemfile
gem 'stripe'
bundle install
require が必要な gem の場合:
# Gemfile
gem 'stripe', require: 'stripe'
または初期化ファイルで:
# config/initializers/stripe.rb
require 'stripe'
原因9:initializer のロード順
# config/initializers/api_client.rb
ApiClient.configure do |c|
# ApiClient が未定義の場合エラー
end
initializers は eager_load の前に実行されるため、Zeitwerk が未ロードのクラスを参照するとエラー。
対処1: 明示的に require(gem の場合)
require 'api_client'
ApiClient.configure do |c|
# ...
end
対処2: to_prepare で遅延実行
# config/initializers/setup.rb
Rails.application.config.to_prepare do
ApiClient.configure do |c|
# ...
end
end
原因10:concern と config
# app/models/concerns/searchable.rb
module Searchable
end
# app/models/article.rb
class Article < ApplicationRecord
include Searchable
end
app/models/concerns/ は autoload_paths に含まれるが、名前空間は無視されます。つまり Searchable をそのまま参照できる。
注意: Models::Searchable のような名前空間にしたい場合は、app/models/searchable.rb に置くか、ディレクトリ構造を整える必要があります。
zeitwerk:check の活用
Rails のコマンドで autoload 不整合をチェック。
実行
bin/rails zeitwerk:check
正常時
Hold on, I am eager loading the application.
All is good!
エラー時
Hold on, I am eager loading the application.
expected file app/models/api/v1/user.rb to define constant Api::V1::User, but didn't
該当ファイルの定数定義を修正。
CI/CD で実行
# .github/workflows/ci.yml
- name: Check autoloader
run: bin/rails zeitwerk:check
本番デプロイ前に autoload 問題を防げます。
autoload のログ確認
# config/application.rb
config.after_initialize do
Rails.autoloaders.log! # autoload動作をログ出力
end
または:
# 一時的に有効化
RAILS_AUTOLOADERS_LOG=1 bin/rails server
これで「どの定数がどのファイルからロードされたか」が追跡できます。
Classic Autoloader からの移行
Rails 6以前の Classic Autoloader を使っているプロジェクトの移行。
現在のモード確認
Rails.autoloaders.zeitwerk_enabled?
# => true なら Zeitwerk
または:
Rails.application.config.autoloader
# => :zeitwerk または :classic
Zeitwerk 化の手順
ステップ1:load_defaults を設定
# config/application.rb
config.load_defaults 7.0 # または 8.0
これで Zeitwerk がデフォルトに。
ステップ2:zeitwerk:check 実行
bin/rails zeitwerk:check
エラーが出るファイルを一つずつ修正。
ステップ3:acronym 設定
頭字語を使うクラスがあれば:
# config/initializers/inflections.rb
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym "API"
inflect.acronym "CSV"
# ...
end
ステップ4:複数定数の分割
1ファイル複数定数の構造を、Zeitwerk規約に合わせて分割。
ステップ5:require_dependency の削除
# 削除
require_dependency 'some_file'
ステップ6:lib/ の扱い見直し
# 必要に応じて autoload_paths に追加
config.autoload_paths += %W(#{config.root}/lib)
config.eager_load_paths += %W(#{config.root}/lib)
または app/ に移動。
開発環境 vs 本番環境
開発環境(development)
eager_load = false のため、必要時のみロード:
- メモリ効率良い
- 起動が高速
- 一部のファイル問題は気付かない可能性
本番環境(production)
eager_load = true で起動時に全ロード:
- すべてのファイルが読まれる
- タイポ等は起動時に発覚
- メモリ使用量は増える
ローカルで本番モード再現
開発中にも production 相当の挙動を試したい場合:
# config/environments/development.rb
config.eager_load = true # 一時的に true に
または:
RAILS_ENV=production bin/rails server
test 環境
config.eager_load = ENV["CI"].present? のような条件設定が一般的:
# config/environments/test.rb
config.eager_load = ENV["CI"].present?
CIでは production 同等の挙動でテスト、ローカルテストでは高速化。
Gem 開発時の Zeitwerk 統合
Rails gem を開発する場合の autoload セットアップ。
gem 内での Zeitwerk 利用
# lib/my_gem.rb
require "zeitwerk"
module MyGem
loader = Zeitwerk::Loader.for_gem
loader.setup
end
Zeitwerk::Loader.for_gem が自動的に lib/my_gem/ 配下を autoload 対象に。
ファイル命名
lib/
├── my_gem.rb
└── my_gem/
├── client.rb # MyGem::Client
├── version.rb # MyGem::VERSION
└── api/
└── v1.rb # MyGem::Api::V1
Engine gem
Rails Engine の場合:
# lib/my_engine/engine.rb
module MyEngine
class Engine < ::Rails::Engine
isolate_namespace MyEngine
end
end
isolate_namespace で namespace 分離。app/ 配下のファイルは自動 autoload。
ActiveSupport::Autoload との違い
Rails 内部や一部 gem で使われる古い手法:
module Api
extend ActiveSupport::Autoload
autoload :Client
autoload :Request
end
これは明示的に autoload を登録する方式。Zeitwerk と混在すると問題が起きるため、新規 gem では Zeitwerk 推奨。
トラブルシューティング
Zeitwerk::NameError vs NameError
エラーは2種類あります:
| エラー | 意味 |
|---|---|
Zeitwerk::NameError | ファイル存在するが、期待する定数が定義されていない |
NameError | 定数自体が見つからない |
「expected file X to define constant Y」
Zeitwerk::NameError: expected file app/models/vat.rb to define constant Vat, but didn't
原因: ファイル名と定数名の不一致(典型的に acronym 問題)
対処: acronym 設定、またはファイル名・クラス名を一致させる
「uninitialized constant X::Y」
NameError: uninitialized constant Api::V1::User
原因: そもそも該当ファイルが存在しないか、autoload_paths 外
対処: ファイル配置確認、autoload_paths追加
initializer 内で NameError
# config/initializers/setup.rb
SomeService.configure { ... }
# => NameError
対処: to_prepare で遅延実行
Rails.application.config.to_prepare do
SomeService.configure { ... }
end
Rails console で動くが server で動かない
console は autoload が動的に効きますが、production server では eager_load 時に問題発覚:
RAILS_ENV=production bin/rails zeitwerk:check
事前に確認。
gem の名前空間と衝突
# app/models/stripe.rb(自作モデル)
class Stripe
end
# Stripe gem も存在
require 'stripe'
対処: 自作モデルを別名にする
# app/models/stripe_account.rb
class StripeAccount
end
Spring を完全に削除(古いRails)
# Gemfile
# gem 'spring' # 削除
bundle install
Rails 7.1+ では Spring は廃止されています。
Sprockets と Zeitwerk の競合
app/assets/ 内のアセットファイルが間違って autoload 対象になる場合:
# config/application.rb
Rails.autoloaders.main.ignore(
Rails.root.join("app/assets")
)
よくある質問(FAQ)
Q1. Rails 7/8 でも require は必要ですか?
app/ 配下のクラスには不要(Zeitwerk が自動ロード)。 gem や Ruby 標準ライブラリには必要:
require 'json'
require 'stripe'
Gemfile で require: 'stripe' していれば、自動的に require されます。
Q2. lib/ ディレクトリのファイルを使いたい
選択肢:
A. autoload_paths に追加
config.autoload_paths += %W(#{config.root}/lib)
config.eager_load_paths += %W(#{config.root}/lib)
B. app/ 配下に移動(推奨)
mv lib/services app/services
Q3. acronym 設定の確認方法
# console で
"vat".camelize
# => "VAT" になっていれば設定済み
"csv_importer".camelize
# => "CSVImporter"
Q4. クラスを再ロード(reload)する方法
# console で
reload!
または:
Rails.application.reloader.reload!
開発環境ではファイル変更で自動的に再ロード。
Q5. constantize で NameError
"User".constantize
# => User クラス取得
"NonExistent".constantize
# => NameError
safe_constantize を使うと nil を返す:
"NonExistent".safe_constantize
# => nil
Q6. 名前空間モジュールを別ファイルにすべき?
app/models/
├── api.rb # module Api
└── api/
├── client.rb # Api::Client
└── v1/
└── request.rb # Api::V1::Request
Zeitwerk 規約ではモジュール Api は app/models/api.rb に存在することが期待されます。ファイルが無い場合は自動で空モジュールが生成されますが、明示的に書く方が無難。
Q7. テンプレートで NameError
<%= @user.name %>
<% # @user が nil の場合は別エラー(NoMethodError)%>
ビューでの NameError は ローカル変数の typo の可能性:
<%# render の引数渡し漏れ %>
<%= render "user_card", user: @user %>
部分テンプレート内で:
<%# locals: (user:) -%>
<%= user.name %>
Q8. テストで NameError
# spec/models/user_spec.rb
require "rails_helper"
RSpec.describe User do
# ...
end
rails_helper が Rails.application を ロードしていないと autoload が効きません。require "rails_helper" を必ず先頭に。
Q9. 環境別の挙動
# development: 必要時にロード(lazy)
# test: 設定次第
# production: 起動時に全ロード(eager)
production で問題に気づくケースが多いため、CIで eager_load=true 推奨。
Q10. ActiveSupport::Autoload は使うべきか?
新規開発ではZeitwerk推奨。ActiveSupport::Autoload は古いコードの互換性目的。
Q11. Engine gem との競合
Engine gem が autoload_paths を追加することで、メインアプリの定数と衝突する場合:
# 該当 gem の Engine.rb 確認
# isolate_namespace の有無を確認
isolate_namespace していない gem は名前空間衝突しやすい。
Q12. Zeitwerk のドキュメントは?
公式ドキュメント:
関連エラーとの違い
NoMethodError nil:NilClass
@user.name
# @user が nil → NoMethodError
定数自体は存在するが、メソッド呼び出し対象がnil。詳細はnil:NilClass の記事。
LoadError
require 'non_existent'
# => LoadError
ファイル自体が見つからない場合。
Zeitwerk::NameError
Zeitwerk::NameError: expected file X.rb to define constant Y
ファイルはあるが、期待する定数が定義されていない。
ArgumentError: wrong number of arguments
メソッド呼び出しの引数数違い。定数とは無関係。
違いの一覧
| エラー | 発生原因 |
|---|---|
| NameError uninitialized constant | 定数が見つからない |
| Zeitwerk::NameError | ファイルあるが定数定義間違い |
| LoadError | ファイル自体が見つからない |
| NoMethodError | メソッド呼び出し対象がnil/不適切 |
| ArgumentError | メソッド引数の数や型違い |
参考リンク・関連資料
Ruby / Rails 公式
- Autoloading and Reloading Constants(公式Guide) – 公式ガイド
- Zeitwerk GitHub – Zeitwerk公式リポジトリ
- ActiveSupport::Inflector – acronym設定
関連 Gem
- Bootsnap – Rails起動高速化
関連記事(本サイト)
- undefined method nil:NilClass エラー対処 – nilエラー
- ActiveRecord::RecordNotFound エラー対処 – レコード不在
- ActionController::RoutingError エラー対処 – ルーティング
- Rails 8 アップグレードガイド – Rails 8 全般
- Solid Queue 使い方 – Rails 8 Solid Trifecta
- Propshaft 使い方 – Rails 8 アセット
- MySQL 1146 Table doesn’t exist – 関連エラー
まとめ
NameError: uninitialized constant は Ruby/Rails で頻出するエラーですが、Zeitwerk の規約を理解すれば確実に対処できます。要点を再整理します。
- 本質: Rubyがその定数を見つけられないエラー
- Zeitwerk 規約: ファイル名(スネークケース)= 定数名(キャメルケース)
- ディレクトリ = 名前空間:
api/v1/user.rb→Api::V1::User - acronym: VAT/CSV/JSON 等は
inflect.acronymで設定 - 1ファイル1定数: 複数定数定義は分割
- lib/ の扱い: 標準では autoload 対象外、必要なら追加
- zeitwerk:check: CI/CDで実行して事前検出
- eager_load: production は起動時に全ロード
- initializer: 早期ロード問題は
to_prepareで対処 - Classic からの移行: load_defaults 7.0+ で Zeitwerk 化
これらの知識は、Rails アプリの設計・リファクタリング・本番デプロイ・Gem 開発などあらゆる場面で活用できます。本記事をブックマークしておけば、uninitialized constant エラーに遭遇した時の対応が大幅に効率化されます。
本記事は2026年6月時点の情報をもとに、Ruby on Rails 7.x / 8.x、Zeitwerk 最新版での動作確認・公式ドキュメントに基づき作成しています。Rails のバージョンによって挙動が異なる場合があるため、最新の情報はRails公式ガイドもあわせてご確認ください。
-
前の記事
【完全リファレンス】Linuxでファイルの差分を確認する方法|diff・colordiff・vimdiff完全ガイド 2026.06.26
-
次の記事
Linuxでコマンドの実行時間を計測する方法|timeコマンド完全解説 2026.06.26
コメントを書く