【问题标题】:Is there a way to enforce a schema for a JSON field within a Postgresql record in Rails?有没有办法在 Rails 的 Postgresql 记录中强制执行 JSON 字段的模式?
【发布时间】:2016-10-17 22:02:09
【问题描述】:

我正在涉足 Postgres 中的 json 字段。所以我使用 activerecord 进行大多数验证。但是,我想添加一个 json 字段并能够对其进行验证。有没有一种干净的方法可以做到这一点?我想我总是可以创建自己的验证函数,但似乎有更好的方法可以利用 json 模式?有人成功了吗?

【问题讨论】:

  • “验证”是什么意思?您想确保放入数据库的 JSON 是有效的 JSON?您想确保 JSON 符合某种结构吗?您希望 Rails/ActiveRecord 执行验证还是数据库?还有什么?
  • 我认为他们的意思是使用 json 字段验证用户
  • 我认为他在谈论使用 JSON 模式来验证 JSON 是否符合某种结构。 github.com/ruby-json-schema/json-schema
  • @muistooshort 我的意思是让 ActiveRecord 验证 json 是否符合某种结构

标签: ruby-on-rails json postgresql ruby-on-rails-4 rails-activerecord


【解决方案1】:

您可以使用json-schema gem:

schema = {
  "type" => "object",
  "required" => ["a"],
  "properties" => {
    "a" => {"type" => "integer"}
  }
}
JSON::Validator.validate(schema, { "a" => 5 }) 
# => true
JSON::Validator.validate(schema, { "a" => "five" })
# => false 

请注意,这是广义上的验证器 - 不是可以直接与 ActiveRecord 一起使用的验证器。

Writing a custom ActiveModel validator 不过很简单:

require "json-schema"
class SchemaValidator < ActiveModel::EachValidator

  def validate_each(record, attribute, value)
    # Looks for a JSON schema as a class constant
    c = "#{attribute.upcase}_SCHEMA"
    begin 
      schema = record.class.const_get(c)
    rescue NameError => e
      # re-raise exception with a more descriptive message
      raise( 
        $!, 
        "Expected #{record.class.name}::#{c} to declare a JSON Schema for #{attribute}", 
        $!.backtrace
      )
    end
    unless JSON::Validator.validate(schema, value)
      record.errors.add(attribute, 'does not comply to JSON Schema')
    end
  end
end

然后我们可以这样使用它:

class Thing < ActiveRecord::Base
  FOO_SCHEMA = {
    "type" => "object",
    "required" => ["a"],
    "properties" => {
      "a" => {"type" => "integer"}
    }
  }

  validates :foo, schema: true
end

【讨论】:

  • 很棒的答案,谢谢!一个额外的问题。你能让模式动态吗?假设我有一个付款模型,并且 json 字段称为拆分。有没有办法让一个实例的 split 键等于 { split_1: 45, split_3: 56} 并允许它等于 { split_2: 45, split_4: 56} (不同的键)?
  • 是的,我想有。您可以在 record 上查找定义架构的类或实例方法,而不是在 validate_each 方法中查找常量。
【解决方案2】:

您还可以在数据库级别检查 json。据我所知,PostgreSQL 中有两个库可以验证 JSON:

一旦你安装了其中一个,你可以这样做:

ALTER TABLE my_table ADD CONSTRAINT data_is_valid CHECK (validate_json_schema('{/*your schema here */}', my_json));

如果您使用的是 Postgres JSON 模式,并且:

ALTER TABLE my_table ADD CONSTRAINT data_is_valid CHECK (is_jsonb_valid('{/*your schema here */}', my_json));

如果您使用的是 is_jsonb_valid。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-19
  • 1970-01-01
  • 2019-01-09
  • 1970-01-01
  • 2011-03-28
  • 1970-01-01
  • 2011-07-29
相关资源
最近更新 更多