我有一个看起来像
的文件#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
现在,当我从rails c
运行代码时,我有一个错误
> ::Account::Authenticate::AuthenticateError
=> NameError (uninitialized constant Account::Authenticate::AuthenticateError)
> ::Account::Authenticate.constants
=> [:Base, :ViaToken]
因此,Rails看不到AuthenticateError类。但是,当我将从此文件夹中创建一个嵌套类时,例如
=> Account::Authenticate::ViaToken
> ::Account::Authenticate.constants
=> [:Base, :AuthenticateError, :ViaToken]
AuthenticateError类现在可见
> ::Account::Authenticate::AuthenticateError
=> Account::Authenticate::AuthenticateError
解决此问题的解决方案是创建一个单独的文件authenticate_error.rb,该文件从一开始就可以使用,但是对于我来说,该解决方案并不理想。是否有任何解决方案来预加载所有类或SMTH?
(带有导轨的Ruby 2.6 6.0.0.rc2(
我在将导轨6.0.2应用于Ubuntu 18.04服务器时经历了同样的问题。
无法加载应用程序:zeitwerk :: nameError:预期文件/home/deploy/myapp/app/models/models/concerns/designation.rb定义常数名称,但没有
我发现问题是 zeitwerk 。Zeitwerk是Rails 6中使用的新的代码加载器引擎。它将成为所有Rails 6 项目的新默认设备,以取代旧的 Classic 引擎。Zeitwerk提供了代码自动加载,急切加载和重新加载的功能。
这是我解决的方式:
导航到项目上的config/application.rb
文件。
在应用程序模块中添加此行以切换到自动加载的classic
模式:
config.autoloader = :classic
这是一个示例:
module MyApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.0
# 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.autoloader = :classic
end
end
您可以在 zeitwerk 上阅读更多信息:了解Rails中的Zeitwerk 6
将Rails应用程序从5.2更新为6.0,还可以击中Zeitwerk Bump!
如果要继续使用您当前正在使用的自动加载模式,请避免Zeitwerk,然后将此行添加到您的应用程序.rb文件(@promisepreston andles and rails doc(
config.autoloader = :classic
如果您想升级到Zeitwerk,则使用的命令是bin/rails zeitwerk:check
(来自本指南文章(。
场景我们最接近这个特定的问题是我们在这样的子文件夹中有一个文件的位置:
#presenters/submission_files/base.rb
module Presenters
module SubmissionFiles
class Base < Showtime::Presenter
def method_call
#code_here
end
end
end
end
删除额外的模块以:
#presenters/submission_files/base.rb
module Presenters
class SubmissionFiles::Base < Showtime::Presenter
def method_call
#code_here
end
end
end
然后,在应用程序中的其他Ruby文件中调用该方法时使用:Presenters::SubmissionFiles::Base.method_call
zeitwerk
遵循conventional file structure
,只要您遵守规则,就可以按需加载项目的类和模块(自动加载(。
# service/account/authenticate/base.rb
module Account
module Authenticate
puts "load service ....."
AuthenticateError = Class.new(StandardError)
class Base
end
end
end
::Account::Authenticate::AuthenticateError # uninitialized constant
::Account::Authenticate::Base # load service ....
::Account::Authenticate::AuthenticateError # OK
您可以看到,您第一次尝试到达常数AuthenticateError
时,日志load service ...
没有显示,因为您不玩zeitwerk
规则:
每当收到加载const
::Account::Authenticate::AuthenticateError
的请求时,首先会检查并返回如果已经加载了常数,否则会查找与常数::Account::Authenticate::AuthenticateError
相对应的文件/account/authenticate/authenticate_error.rb
,以找到该常数定义,但找不到它。在步骤2上,当您调用
::Account::Authenticate::Base
时,它可以找到文件/account/authenticate/base.rb
并加载它,在此期间,它也加载了在该文件上定义的常数AuthenticateError
,现在我们拥有常数::Account::Authenticate::AuthenticateError
,并且当然,步骤3可以。
现在让我们尝试使用zeitwerk
规则,我创建一个文件/account/authenticate/authenticate_error.rb
如下
# service/account/authenticate/authenticate_error.rb
module Account
module Authenticate
puts "load error ....."
AuthenticateError = Class.new(StandardError)
end
end
并尝试在步骤1
上尝试该常数$ spring stop
$ rails c
> ::Account::Authenticate::AuthenticateError
load error .....
=> Account::Authenticate::AuthenticateError
它起作用,因为zeitwerk
找到了文件account/authenticate/authenticate_error.rb
。(请注意,文件名/____authenticate_error.rb
仍然有效(
我的想法:我认为您可以安全地使用模块::Account::Authenticate
中常数AuthenticateError
,如果您想将这些错误常数公开到外部,则可以创建文件/account/authenticate/error.rb
# service/account/authenticate/error.rb
module Account
module Authenticate
module Error
AuthenticateError = Class.new(StandardError)
end
end
end
然后,您可以访问::Account::Authenticate::Error::AuthenticateError
,我认为它比将AuthenticateError
放入base.rb
中更清楚。
我能够通过不尝试对抗导轨6来解决它。Zeitwerk
自动加载某些预期文件夹,其中包括应用程序/型号,应用程序/控制器,应用程序/助手等。
我创建了一个文件夹app/helpers
并将我的services
文件夹移入其中。
就是这样!