我最近将我的应用程序从rails 6升级到了rails 7,由于zeitwerk命名约定,我面临一个问题。我有一个下面的文件,我想自动加载:
app/models/dw/hospital.rb
module DW
class Hospital < DataWarehouse
def self.columns
super.reject{|column| column.name == 'tableau_user' }
end
end
end
我尝试通过在application.rb
文件中添加以下行来自动加载此文件:
config.autoload_once_paths << 'app/models/dw'
但是当我启动服务器时,我得到了以下错误:
expected file app/models/dw/hospital.rb to define constant Hospital, but didn't (Zeitwerk::NameError)
我不知道为什么会抛出这样的错误,因为常量已经定义好了。我怀疑这是因为我在类之前定义的模块。如果有人想解决这个问题,请告诉我。我在这方面已经陷得太久了。
因为您已经将app/models/dw
添加到自动加载路径,所以必须定义Hospital
,但您的定义是按名称空间的DW::Hospital
。您不需要触摸自动加载配置,app/models
已经在autoload_paths
:中
>> ActiveSupport::Dependencies.autoload_paths
=>
...
"/home/alex/code/stackoverflow/app/jobs",
"/home/alex/code/stackoverflow/app/mailers",
"/home/alex/code/stackoverflow/app/models", # <======
...
这些就是所谓的根目录。这意味着相对于app/models
的文件结构必须与模块/类名相对应。
因此,如果在任何根目录中都有dw/hospital.rb
,则必须定义已经定义的Dw::Hospital
。你也必须注意屈折,它应该是Dw
,除非你有首字母缩略词屈折规则或时代周刊屈折:
>> "dw".camelize
=> "Dw"
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.acronym "DW"
end
>> "dw".camelize
=> "DW"
如果你必须嵌套根目录,你应该有一个很好的理由:
# if you want it to be reloadable,
# use `autoload_paths` instead of `autoload_once_paths`
config.autoload_paths << Rails.root.join("app/models/dw")
# app/models/dw/hospital.rb
class Hospital
end
但正如Xavier在评论中提到的那样,没有必要进行这种配置。使用默认配置,不要使设置变得不必要的复杂。
看起来像是大写的问题
通常,PascalCase
(也称为CamelCase
(类名必须与snake_case
文件名相对应。相同的规则适用于命名空间和文件夹
但是dw
文件夹中有DW
(而不是Dw
(
你可以创建一些类似的初始值设定项
# config/initializers/zeitwerk.rb
Rails.autoloaders.each do |autoloader|
autoloader.inflector = Zeitwerk::Inflector.new
autoloader.inflector.inflect(
'dw' => 'DW',
# other special cases
)
end