最近,我将我的应用程序从rails 6升级到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)我不知道为什么会抛出这样的错误,因为常量已经定义好了。我怀疑这是因为我在类之前定义的模块。如果有人想解决这个问题,请告诉我。我被困在这里太久了。
发布于 2022-09-15 21:03:33
因为您已经将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", # <======
...这就是所谓的https://github.com/fxn/zeitwerk#root-directories-and-root-namespaces。这意味着相对于app/models的文件结构必须对应于模块/类名。
因此,如果在任何根目录中都有dw/hospital.rb,那么就必须定义Dw::Hospital,这是您已经定义的。你也必须注意拐点,它应该是Dw,除非你有缩略词拐点规则或zeitwerk拐弯处:
>> "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但是正如泽维尔在评论中提到的那样,没有必要进行这种配置。使用默认配置,不要不必要地使设置复杂化。
发布于 2022-09-15 20:57:43
看起来大写的问题
通常,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
)
endhttps://stackoverflow.com/questions/73737036
复制相似问题