我上了几节课 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")
也会失败
编辑:这是一个加载顺序问题。在类上运行之后,该常量立即可用,因为随后会加载该类。但是,通过尝试加载此类,模块将在加载时从父类继承,并且模块代码仍会在设置常量之前运行。
是否有某种类似继承的钩子,但允许所有内容预加载?
实际上,这里的问题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
只是一个开放本征类的普通旧类方法。这与在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" }
由于意图不明确,因此被视为不良形式。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句