3

Rails 6 切换到 Zeitwerk 作为默认的自动加载器。Zeitwerk 将加载 /app 文件夹中的所有文件,无需命名空间。这意味着,现在可以直接调用 app/services/demo/test_service.rb 中的 TestService 服务对象,例如TestService.new().call

然而,命名空间有助于在更复杂的 Rails 应用程序中组织对象,例如API::UsersController,或者对于我们使用 Registration::CreateAccount、Registration::AddDemoData 等的服务。

rails 指南建议的一种解决方案是从 application.rb 中的自动加载器路径中删除路径,例如config.autoload_paths -= Dir["#{config.root}/app/services/demo/"]. 然而,这感觉就像一个猴子补丁,用于硬塞旧方式或将对象组织到新的轨道方式中。

命名空间对象的正确方法或组织它的 rails 6 方法是什么,而不仅仅是强制 rails 进入旧方式?

4

2 回答 2

4

说 Zeitwerk 消除了“命名空间的需要”是不正确的。Zeitwerk 确实会自动加载app(除了assetsjavascriptsviews)的所有子目录。下的任何目录app都加载到“根”命名空间中。但是,Zeitwerk 还为这些根目录下的任何目录“自动激活”模块。所以:

/models/foo.rb => Foo
/services/bar.rb => Bar
/services/registration/add_demo_data.rb => Registration::AddDemoData

如果您已经习惯于从“非标准”目录加载常量(通过添加到config.autoload_paths),通常不会有太大变化。不过,有几个案例确实需要一些调整。第一个是您要迁移的项目只是将app自身添加到自动加载路径中。在经典(Rails 6 之前)中,这允许您使用app/api/base.rbto API::Basecontains ,而在 Zeitwerk 中它希望它只包含Base. 就是您上面提到的情况,建议将该目录从自动加载路径中排除。另一种选择是简单地添加一个包装器目录,如app/api/api/base.rb.

第二个需要注意的问题是 Zeitwerk 如何从文件名中推断出常量。从 Rails 迁移指南:

classic模式从丢失的常量名(下划线)推断文件名,而 zeitwerk 模式从文件名推断常量名(camelize)。这些助手并不总是彼此相反,尤其是在涉及首字母缩略词的情况下。例如,"FOO".underscore"foo",但是,"foo".camelize不是。"Foo""FOO"

所以,/api/api/base.rb实际上等于Api::Base在 Zeitwerk 中,而不是API::Base.

Zeitwerk 包含一个 rake 任务来验证项目中的自动加载:

% bin/rails Zeitwerk:check
Hold on, I am eager loading the application.
expected file app/api/base.rb to define constant Base
于 2020-08-05T05:57:10.137 回答
0

我发布了单独的答案,但实际上接受的答案包含所有好的信息。由于我的评论超出了允许范围,因此我选择为那些遇到类似问题的人添加单独的答案。

我们在应用程序下创建了“组件”,我们在其中分离了特定于域的命名空间/包。它们与一些“非组件”Rails 部件共存,这些部件很难在组件下移动。使用经典的自动加载器,我们添加#{config.root}/app了我们的 autoload_paths。

Zeitwerk 的此设置失败,并且"#{config.root}/app"从 autoload_paths 中删除没有帮助。rmlockerd 建议移到app/api/下面/app/api/api让我想到在这个目录下创建单独'app/components'和移动所有组件并将这个路径添加到autoload_paths. Zeitwerk 喜欢这个。

于 2021-03-12T19:09:12.537 回答