簡體   English   中英

Ruby:如何在模塊加載到其父類中之前預先加載類內容

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM