我有一个包含两个文件的 Rails 文件夹:
app/hub_spot/client.rb:
module HubSpot
class Client
app/hub_spot/create_contact_form.rb:
module HubSpot
class CreateContactForm
当我运行 zeitwerk 检查时,我得到:
expected file app/hub_spot/client.rb to define constant Client, but didn't
如果我添加:
config.autoload_paths << Rails.root.join("app/hub_spot")
config.eager_load_paths << Rails.root.join("app/hub_spot")
然后我收到一个新的错误:
expected file app/hub_spot/create_contact_form.rb to define constant CreateContactForm, but didn't
它似乎对这两个文件的抱怨不同?有什么方法可以告诉 Zeitwerk 查看文件夹中的模块名称吗?
由于历史原因/懒惰的原因,Rails 使用了一种相当古怪的自动加载器设置。它实际上更侧重于按目的组织顶级常量,而不是封装等烦人的东西。
目录的每个子目录
app
都会自动添加为 Zeitwerk 中的根目录。Zeitwork 期望在根目录中找到顶级常量,在将文件路径解析为常量时会忽略这些常量。Rails 仍然使用术语autoloading_paths
和,eager_load_paths
这是从 Rails 6 之前使用的经典自动加载器中保留下来的,两者大致相同。因此,如果您将文件移至
app/foo/hub_spot/client.rb
Zeitwork,则可以轻松找到它。请注意,根级文件夹的名称实际上无关紧要(除了我们人类)。您可以将其与典型的 gem 设置进行比较,该设置只有一个根目录(
lib
),并且代码应该嵌套在具有 gem 名称的模块和文件夹中。虽然您可以将
app
目录本身添加为自动加载根,但我还是要警惕潜在的错误。实际上,放入代码的唯一原因
app
(除了其他开发人员的期望)是您想要使用 Rails 自动加载器设置,因此只需接受这种奇怪之处并添加另一级目录嵌套,这样它至少是始终奇怪的。您还可以设置 Zeitwerk 来加载您的代码,以
lib/my_namespace
反映 gem 的设置方式(这并不那么古怪)。它不会。它告诉你,它期望常量在顶层定义,因为从它的角度来看,文件路径只是
/create_contact_form.rb
。它只是检查不同的文件。config.autoload_paths << Rails.root.join("app/hub_spot")
是完全多余的,因为无论如何它都会默认发生。看:
修复命名空间问题你目前的情况:
应用程序/hub_spot/客户端.rb 应用程序/hub_spot/create_contact_form.rb
这些文件位于 app/hub_spot/ 中,因此 Zeitwerk 会期望它们位于 HubSpot 模块中。但 Zeitwerk 不会根据文件夹名称本身推断出 HubSpot 模块 - 您必须明确指定它。
解决方案:重新排列文件结构或模块定义 选项 1:将文件夹移动到 app/lib/ 或 app/models/ Zeitwerk 会自动加载 app/ 中的目录(例如模型、控制器等),但默认情况下 app/hub_spot/ 不是其中之一。
相反,将您的文件夹放在 app/lib/hub_spot/ 内并包含: