2

我有几个有常数的类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")也失败了

编辑:这是一个加载顺序问题。在类上运行之后,该常量可用,因为随后加载了该类。但是通过尝试预先加载这个类,模块会在预先加载时从父类继承,并且模块代码仍然在设置常量之前运行。

是否有某种类似于继承的钩子,但它允许所有内容都预加载?

4

1 回答 1

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只是一个普通的旧类方法,它打开了特征类。这与 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" }被认为是不好的形式,因为意图很不明确。

于 2019-12-08T01:34:23.317 回答