[英]Ruby: How to eager load class contents before a module gets loaded in its parent class
我有一些具有恆定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" }
被視為不良形式,因為意圖非常不清楚。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.