Rails从5.0升级至7.0.4.3后遇NameError:未初始化常量Api
解决Rails 7升级后
uninitialized constant Api (NameError)问题 问题场景
将Ruby从2.6.6升级到3.2.2、Rails从5.x升级到7.0.4.3后,启动rails s时出现以下错误:
=> Booting Puma => Rails 7.0.4.3 application starting in development => Run `bin/rails server --help` for more startup options Exiting /mnt/c/Users/akaram/Desktop/Ruby/hire-right-integration/config/initializers/api_v1_log.rb:2:in `<top (required)>': uninitialized constant Api (NameError) Api::V1::Log.logger = Logger.new(Api::V1::Log::LogFile) ^^^^^
涉及核心文件:
config/initializers/api_v1_log.rb:
unless ENV['ASSET_PRECOMPILE'].present? Api::V1::Log.logger = Logger.new(Api::V1::Log::LogFile) Api::V1::Log.logger.level = 'info' end
app/models/api/v1/log.rb:
module Api::V1 class Log LogFile = Rails.root.join("log", "api_v1_#{Rails.env}.log") class << self cattr_accessor :logger delegate :debug, :info, :warn, :error, :fatal, :to => :logger end end end
- 已在
config/application.rb添加配置:
config.eager_load = true config.autoload_paths << Rails.root.join('app') config.autoload_paths += %W(#{config.root}/app/models/api/v1/)
问题原因
Rails 7默认采用Zeitwerk作为自动加载器,替换了Rails 5的经典自动加载机制,核心冲突点:
- 初始化器执行时机早于模型类的自动加载流程,此时
Api::V1::Log常量尚未被加载 module Api::V1的嵌套定义方式不符合Zeitwerk的规范,导致模块无法被自动识别- 手动添加的
autoload_paths在Zeitwerk机制下优先级极低,甚至不生效
解决方案
方案1:手动加载模型文件到初始化器
直接在初始化器中提前加载目标模型文件,确保常量存在:
unless ENV['ASSET_PRECOMPILE'].present? # 手动加载Log模型文件 require Rails.root.join('app/models/api/v1/log') Api::V1::Log.logger = Logger.new(Api::V1::Log::LogFile) # 注意:将字符串'info'改为Logger常量,新版Ruby/Rails不支持字符串设置级别 Api::V1::Log.logger.level = Logger::INFO end
方案2:延迟初始化到Rails加载完成后
利用config.after_initialize钩子,在所有模型加载完成后再执行初始化逻辑:
修改config/initializers/api_v1_log.rb为:
Rails.application.config.after_initialize do next if ENV['ASSET_PRECOMPILE'].present? Api::V1::Log.logger = Logger.new(Api::V1::Log::LogFile) Api::V1::Log.logger.level = Logger::INFO end
方案3:适配Zeitwerk自动加载规范(推荐长期方案)
Zeitwerk要求每个模块对应独立的目录和文件,按以下步骤调整:
- 创建
app/models/api.rb定义Api模块:
module Api end
- 创建
app/models/api/v1.rb定义Api::V1模块:
module Api::V1 end
- (可选)将
app/models/api/v1/log.rb的模块定义改为嵌套式(更符合规范):
module Api module V1 class Log LogFile = Rails.root.join("log", "api_v1_#{Rails.env}.log") class << self cattr_accessor :logger delegate :debug, :info, :warn, :error, :fatal, :to => :logger end end end end
- 移除
config/application.rb中手动添加的autoload_paths配置,Zeitwerk默认会自动扫描app目录下的所有文件。
内容的提问来源于stack exchange,提问作者AntonioKaram
相关产品推荐
相关产品推荐

