Ruby:如何在模块加载到其父类中之前急切加载类内容
Posted
技术标签:
【中文标题】Ruby:如何在模块加载到其父类中之前急切加载类内容【英文标题】:Ruby: How to eager load class contents before a module gets loaded in its parent class 【发布时间】:2020-04-01 12:11:24 【问题描述】:我有几个类的常量SCHEMA
class Consumable::ProbeDesign < Consumable
SCHEMA =
"type": "object",
"properties": ,
"required": []
end
class DataModule::WaterDeprivationLog < DataModule
SCHEMA =
"type": "object",
"properties":
"water_amount": "type": "decimal",
"notes": "type": "string"
,
"required": []
end
它们是 STI 方案中基类的子类
class Consumable < ApplicationRecord
include SingleTableInheritable
end
class DataModule < ApplicationRecord
include SingleTableInheritable
end
然后我有一个模块,它需要为从包含该模块的类继承的所有类动态访问该常量
module SingleTableInheritable
extend ActiveSupport::Concern
included do
def self.inherited(subclass)
subclass.class_eval do
schema = subclass::SCHEMA # NameError: uninitialized constant #<Class:0x0000560848920be8>::SCHEMA
# then do some validations that rely on that schema value
end
super
end
end
end
但在执行时以及在如何调用它的上下文中,它找不到模块并返回NameError: uninitialized constant #<Class:0x0000560848920be8>::SCHEMA
请注意,subclass.const_get("SCHEMA")
也会失败
编辑:这是一个加载顺序问题。在类上运行之后,该常量可用,因为随后加载了该类。但是通过尝试预先加载这个类,模块会在预先加载时从父类继承,并且模块代码在设置常量之前仍然运行。
是否有某种类似于继承但允许所有内容预加载的钩子?
【问题讨论】:
【参考方案1】:这里的问题实际上是Module#included
将始终在评估子类的主体之前运行。但Module#included
并不是添加验证或回调的唯一方法。
您可以定义自己的“钩子”:
module SingleTableInheritance
extend ActiveSupport::Concern
class_methods do
def define_schema(hash)
class_eval do
const_set(:SCHEMA, hash)
if self::SCHEMA["type"] == "object"
validates :something ...
end
end
end
end
end
define_schema
只是一个普通的旧类方法,它打开了 eigenclass。这与在 Rails 和 Ruby 中普遍使用的模式相同,从生成 setter 和 getter 到验证甚至回调。
用法:
class DataModule::WaterDeprivationLog < DataModule
define_schema(
type: "object",
properties:
water_amount: type: "decimal",
notes: type: "string"
,
required: []
)
end
您还应该知道,您使用的“短”哈希语法会将键强制转换为符号:
irb(main):033:0> "foo": "bar"
=> :foo=>"bar"
如果您想将字符串作为键,请改用 hashrockets =>
。 "foo": "bar"
被认为是不好的形式,因为意图很不明确。
【讨论】:
这看起来不错。让我运行它以确保。奇怪的散列语法来自这样一个事实,即这些最初是 json 文件,我试图将其作为散列直接放在类中。 很棒的答案,它不仅解决了我的问题,还让我了解了约定。谢谢@max以上是关于Ruby:如何在模块加载到其父类中之前急切加载类内容的主要内容,如果未能解决你的问题,请参考以下文章
Angular 8 急切加载模块(包括应用程序模块)不会出现在 chrome 开发工具中