You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 7中app目录下添加自定义foo文件夹遇常量加载错误

Rails 7自定义app/foo目录无法识别命名空间模块的解决方案

问题重现

在Rails 7的app/foo目录下创建bar.rb:

module Foo
  class Bar
  end
end

执行Foo::Bar.new时报错uninitialized constant Foo (NameError),但去掉命名空间只保留class Bar时,Bar.new能正常运行;添加config.autoload_paths << "#{root}/app/foo"也无效,将foo放到app/api或app/models下则能正常识别Foo::Bar。

核心原因

Rails 7默认使用Zeitwerk作为自动加载器,它的核心规则是:

  • app目录下的直接子目录(如app/models、app/controllers)属于根命名空间加载目录,这些目录里的文件直接对应根命名空间下的类/模块(比如app/models/user.rb对应User,而非Models::User)。
  • 若未显式配置,app/foo会被当成根命名空间加载目录,而非Foo命名空间的根目录,因此Zeitwerk只会在根命名空间找Bar,不会识别Foo命名空间。

解决方法

在config/application.rb中显式告知Zeitwerk,app/foo是Foo命名空间的根目录:

# config/application.rb
module YourAppName
  class Application < Rails::Application
    config.load_defaults 7.0

    # 配置app/foo对应Foo命名空间
    Rails.autoloaders.main.push_dir(Rails.root.join("app/foo"), namespace: :Foo)
  end
end

配置后,有两种写法都能正常被识别:

  1. 保留命名空间的写法(app/foo/bar.rb):
module Foo
  class Bar
  end
end
  1. 利用Zeitwerk约定简化写法(推荐):
# app/foo/bar.rb
class Bar
end

此时直接调用Foo::Bar.new即可,Zeitwerk会自动将app/foo下的Bar归入Foo命名空间。

补充说明

将foo放到app/api或app/models下能正常工作,是因为这些目录本身是根命名空间加载目录,它们的子目录会被Zeitwerk自动识别为对应命名空间(比如app/models/foo/bar.rb对应Foo::Bar),这和你更新里提到的逻辑一致——app/models/user.rb无需写成Models::User,同理app/foo若不配置,也不会被当成命名空间根目录。

内容的提问来源于stack exchange,提问作者r3b00t

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 08:10:31