我正在使用Single Table Inheritance进行Rails设置,其中每个类的所有属性都存储在JSON Blob中,该Blob的结构在该类唯一的JSON模式文件中定义。
我想针对每个类针对其json模式运行验证,但是每个类的逻辑都是相同的,减去模式本身的路径,这取决于STI类和子类的名称。
此设置依赖于gem'activerecord_json_validator',它指定了验证架构文件的格式以及一些用于验证的助手
所以所需的设置类似于
/app/models/data_generating_module
(从未实例化的抽象STI基类)
class DataGeneratingModule < ActiveRecord::Base
has_and_belongs_to_many :action_coordinates
def self.schema_path
"#{Rails.root}/app/models/json_schemas/#{superclass.to_s.underscore}/#{self.to_s.underscore}.json"
end
validates :module_data, presence: true, json: { message: ->(errors) { errors }, schema: self.schema_path }
end
app / models / sub_sti(实例化的类)
class SubSti< DataGeneratingModule
end
[schema_path
应评估为repo/app/models/json_schemas/data_generating_module/sub_sti.json"
如果我将schema_path
和验证代码留在子类上,则全部正常。
[执行此操作后,可以实例化SubSti
,但是如果我在其上调用.valid?
,则会引发错误,因为调用schema_path
get时,它使用的是超类而不是子类的值。
JSON::Schema::ReadFailed (Read of file at /git/repo/app/models/json_schemas/active_record/base/data_generating_module.json failed)
因此,基本上,如何将所有这些数据移到抽象STI类中以避免重复数据,但是仍然在其中插入子类的适当值?
将其放入继承的钩子中,然后在子类内部进行类逃避使此工作正常:
class DataGeneratingModule < ActiveRecord::Base
def self.inherited(subclass)
subclass.class_eval do
validates :module_data, presence: true, json: { message: ->(errors) { errors }, schema: "#{Rails.root}/app/models/json_schemas/#{subclass.superclass.to_s.underscore}/#{subclass.to_s.underscore.split("/").last}.json" }
end
super
end
end