将类移入嵌套/public目录后Zeitwerk常量缺失问题求助
问题描述
我正在使用packwerk将传统Rails应用重构为packages模块化结构:
- 原目录结构:
- app - services - foo
- 第一次重构后目录结构:
- packages - package_name - services - foo
此时在application.rb中添加了自动加载配置:
class Application < Rails::Application config.load_defaults 6.0 # packwerk files config.paths.add 'packages', glob: '*/{*,*/concerns}', eager_load: true end
Foo服务可通过Foo正常访问。但按照packwerk标准做法,创建public目录并将services移入其中后:
- packages - package_name - public - services - foo
调用Foo开始抛出uninitialized constant错误,尝试PackageName::Services::Foo、PackageName::Foo等路径也无效。
附上zeitwerk.rb初始化文件:
Rails.autoloaders.each do |autoloader| # See inflections.rb for inflector rules autoloader.inflector.inflect( "ai_wrapper" => "AIWrapper", # ActiveAdmin class ) # ignore ActiveAdmin classes: without this line zeitwerk will match constants like Documents or DocumentFields # to /ops/admin classes instead of core/models directories autoloader.ignore(Rails.root.join('packages/ops/admin')) end
解决方案
1. 调整自动加载路径配置
当前config.paths.add的glob规则未覆盖public目录下的内容,需要修改规则让Rails扫描到packages/*/public路径下的文件:
class Application < Rails::Application config.load_defaults 6.0 # packwerk files:包含public目录下的文件 config.paths.add 'packages', glob: '*/public/{*,*/concerns}', eager_load: true end
如果需要同时兼容之前的非public结构和新的public结构,可将glob规则改为:
config.paths.add 'packages', glob: '*{,/public}/{*,*/concerns}', eager_load: true
2. 匹配常量命名与目录结构
按照Zeitwerk自动加载规则,packages/package_name/public/services/foo.rb对应的默认常量是Services::Foo(根命名空间下)。如果希望包内常量归属于PackageName命名空间,需在zeitwerk.rb中设置命名空间映射:
Rails.autoloaders.each do |autoloader| # 保留原有配置... # 为package_name包设置命名空间 autoloader.push_dir( Rails.root.join('packages/package_name/public'), namespace: PackageName ) end
同时要确保foo.rb中的类定义与命名空间匹配:
module PackageName module Services class Foo # 类逻辑 end end end
此时即可通过PackageName::Services::Foo访问该类。
3. 清理缓存并重启服务器
修改自动加载配置后,需清理Rails缓存并重启服务器,确保配置生效:
rails tmp:clear rails server
内容的提问来源于stack exchange,提问作者ntonnelier
相关产品推荐
相关产品推荐

