如何解决Ruby/Rails:在 ApplicationRecord 中包含关注点时的循环依赖
我担心创建一个类宏,我希望该宏可用于 Rails 应用程序中的所有模型。所以我将它包含在 ApplicationRecord 中。代码如下:
# application_record.rb
class ApplicationRecord < ActiveRecord::Base
include ::TestConcern
end
# app/concerns/test_concern.rb
module TestConcern
extend ActiveSupport::Concern
class_methods do
def some_class_macro_all_models_must_have
User.some_class_instance_variable << self
end
end
included do
User.include(UserModule)
end
module UserModule
def self.included(base)
base.class_eval do
def self.some_class_instance_variable
@some_class_instance_variable ||= Set.new
end
end
end
end
end
如您所见,类宏实际上会与模型 User 中的类实例变量进行交互。
这就是为什么,在关注的包含钩子上,我试图class_eval
User 模型来初始化该类实例变量。计划是这样做的,否则任何模型都可以在用户模型中初始化类实例变量之前调用类宏。
然而,这会以 Circular dependency detected while autoloading constant User
出错。据我所知,ApplicationRecord
加载,它包含模块,模块 included
钩子被调用,它引用了 User
模型,因此加载了 User 模型,它继承了来自ApplicationRecord(尚未完成加载),因此会导致循环依赖。
如何避免这种循环依赖悖论,知道很多模型会调用这个类宏,而且那些类可能会在 User 类本身之前加载,所以我什至不能指望定义 some_class_instance_variable
类方法在用户模型本身?
解决方法
经过深思熟虑后,我决定简单地将 some_class_instance_variable 存储在关注点本身中,并且由于模型 User
也称为 some_class_macro_all_models_must_have
,因此我决定包含 UserModule
当它被调用时,有效地消除了循环依赖和加载顺序问题。
真正的代码比这个人为的例子复杂得多,但最终的结果是这样的:
module TestConcern
def self.some_class_instance_variable
@some_class_instance_variable ||= Set.new
end
extend ActiveSupport::Concern
class_methods do
def some_class_macro_all_models_must_have
User.include(UserModule) if self == User
TestConcern.some_class_instance_variable << self
end
end
included do
end
module UserModule
def self.included(base)
base.class_eval do
# Class macro invocations,class method and instance method definitions
end
end
end
end
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。