我有一个看起来像这样的文件
#app/services/account/authenticate/base.rb
module Account
module Authenticate
AuthenticateError = Class.new(StandardError)
class Base < ::Account::Base
def self.call(*attrs)
raise NotImplementedError
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
现在当我运行代码时rails c出现错误
> ::Account::Authenticate::AuthenticateError
=> NameError (uninitialized constant Account::Authenticate::AuthenticateError)
> ::Account::Authenticate.constants
=> [:Base, :ViaToken]
Run Code Online (Sandbox Code Playgroud)
所以 rails 没有看到 AuthenticateError 类。但是当我从这个文件夹创建一个嵌套类时
=> Account::Authenticate::ViaToken
> ::Account::Authenticate.constants
=> [:Base, :AuthenticateError, :ViaToken]
Run Code Online (Sandbox Code Playgroud)
AuthenticateError 类现在可见
> ::Account::Authenticate::AuthenticateError
=> Account::Authenticate::AuthenticateError
Run Code Online (Sandbox Code Playgroud)
这个问题的解决方案是创建一个单独的文件authenticate_error.rb,它从一开始就可以工作,但这个解决方案对我来说并不理想。是否有任何解决方案可以预加载所有类或 smth?
(Ruby 2.6 和 Rails 6.0.0.rc2)
简单的问题,但不知何故,答案让我望而却步。
在使用 Zeitwerk 迁移到 Rails 6 时,我得到:
Please, check the "Autoloading and Reloading Constants" guide for solutions.
(called from <top (required)> at APP_ROOT/config/environment.rb:7)
rails aborted!
Zeitwerk::NameError: wrong constant name Enforce-calls-to-come-from-aws inferred by Module from directory
APP_ROOT/app/junkyard/enforce-calls-to-come-from-aws
Possible ways to address this:
* Tell Zeitwerk to ignore this particular directory.
* Tell Zeitwerk to ignore one of its parent directories.
* Rename the directory to comply with the naming conventions.
Run Code Online (Sandbox Code Playgroud)
这看起来很棒:这是一个垃圾文件夹,永远不应加载,因此忽略它是完全有道理的。
https://github.com/fxn/zeitwerk 上的 Zeitwerk 文档说
tests = "#{__dir__}/**/*_test.rb"
loader.ignore(tests)
loader.setup …Run Code Online (Sandbox Code Playgroud) 在 Rails 6 的 Zeitwerk 模式中,这些代码中的任何一个都折旧了吗?
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.2
# config/application.rb
config.i18n.load_path += Dir[Rails.root.join("config", "locales", "**", "*.{rb,yml}")]
config.i18n.fallbacks = true
# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.
config.autoload_paths += ["#{config.root}/app/queries/"]
# https://gist.github.com/maxim/6503591 (should remove …Run Code Online (Sandbox Code Playgroud) Rails 6+ 的默认自动加载器是 zeitwerk,这似乎比以前的方法有了很大的改进。
但是,zeitwork 遵循 Rails 项目的约定,即其中的任何内容app/*都是自动加载的,不需要命名空间。
这非常app/models/user.rb有用,因为您不必使用Models::User但可以只引用User.
但是,我添加了自己的app/services目录,并将我的服务对象命名为Services::Users::Create,它将映射到app/services/users/create.rb.
Zeitwork 正在抛出我的类常量不存在的错误,因为它是预期的Users::Create(没有Services::前缀)。
无论如何要配置 zeitwork 以Services::在这些实例中要求命名空间?在我看来,阅读代码Services::Users::Create并知道您正在查看app/services/users/create.rb文件要干净得多。
如果只有Users::Create,一般的 Rails 开发人员可能会查找该app/models/users/create.rb文件。
我不喜欢命名它的方法Users::CreateService,它对我来说似乎很不雅。
我不能是唯一一个使用这样的约定的人;有没有其他人遇到过解决方案?我仍在浏览所有 zeitwerk 文档以寻找解决方案,但还没有找到。