Zeitwerk::NameError 由于 Rails 7 中的模块名称

Dev*_*v V 1 ruby ruby-on-rails zeitwerk ruby-on-rails-7

我最近将应用程序从 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
Run Code Online (Sandbox Code Playgroud)

我尝试通过在文件中添加以下行来自动加载此文件application.rb

config.autoload_once_paths << 'app/models/dw'
Run Code Online (Sandbox Code Playgroud)

但是当我启动服务器时,出现以下错误:

expected file app/models/dw/hospital.rb to define constant Hospital, but didn't (Zeitwerk::NameError)
Run Code Online (Sandbox Code Playgroud)

我不确定为什么会抛出这样的错误,因为该常量已经定义了。我怀疑这是因为我在课程之前定义了模块。如果有人如何解决这个问题,请告诉我。我已经被困在这个问题太久了。

Ale*_*lex 6

因为您已添加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",   # <======
...
Run Code Online (Sandbox Code Playgroud)

这些就是所谓的根目录。这意味着文件结构必须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"
Run Code Online (Sandbox Code Playgroud)

如果你必须嵌套根目录,你应该有一个很好的理由:

>> "dw".camelize
=> "Dw"

ActiveSupport::Inflector.inflections(:en) do |inflect|
  inflect.acronym "DW" 
end  

>> "dw".camelize
=> "DW"
Run Code Online (Sandbox Code Playgroud)

但正如 Xavier 在评论中提到的,没有必要进行此配置。使用默认配置,不要使您的设置变得不必要的复杂化。

  • 很好的答案。让我补充一点,需要明确的是,无需修改配置(请删除 config.autoload_once_paths 设置),并且迁移 HOWTO 中对此进行了介绍:https://guides.rubyonrails.org/classic_to_zeitwerk_howto。 html#缩略词 (2认同)