activerecord_json_validator 1.3.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +8 -0
- data/README.md +16 -15
- data/activerecord_json_validator.gemspec +4 -4
- data/gemfiles/Gemfile.activerecord-7.0.x +5 -0
- data/lib/active_record/json_validator/validator.rb +4 -9
- data/lib/active_record/json_validator/version.rb +1 -1
- data/lib/activerecord_json_validator.rb +1 -1
- data/spec/json_validator_spec.rb +27 -97
- metadata +13 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ebef8de77a6adb6c1ea4ff00c49c9e91b843952c4d226f4b149c04df9d585a6
|
4
|
+
data.tar.gz: 7efc4fa80a8dc82343bf1c7148e20f06df2acf127cbdbf9bc98e591e706940db
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f096c0becc38bcdfb81cf70f59174509ea463f088ae02e514c612b397200aaef4dc76e7fd5cfe44ff0bf7c17fe2715a77d41d02101bac55afad19bbb076497a
|
7
|
+
data.tar.gz: e94f0da67f515a20eeb5699be8823c267144eeb36d09c6a1a892d24faab9bc65ca8d2d70edbe4388f088505d75875ede5cd91366393f2b71d42675713f8423ed
|
data/.travis.yml
CHANGED
@@ -3,16 +3,24 @@ language: ruby
|
|
3
3
|
rvm:
|
4
4
|
- 2.4.6
|
5
5
|
- 2.6.3
|
6
|
+
- 2.7.5
|
6
7
|
|
7
8
|
gemfile:
|
8
9
|
- gemfiles/Gemfile.activerecord-4.2.x
|
9
10
|
- gemfiles/Gemfile.activerecord-5.0.x
|
10
11
|
- gemfiles/Gemfile.activerecord-6.0.x
|
12
|
+
- gemfiles/Gemfile.activerecord-7.0.x
|
11
13
|
|
12
14
|
matrix:
|
13
15
|
exclude:
|
14
16
|
- gemfile: gemfiles/Gemfile.activerecord-6.0.x
|
15
17
|
rvm: 2.4.6
|
18
|
+
- gemfile: gemfiles/Gemfile.activerecord-7.0.x
|
19
|
+
rvm: 2.4.6
|
20
|
+
- gemfile: gemfiles/Gemfile.activerecord-7.0.x
|
21
|
+
rvm: 2.6.3
|
22
|
+
- gemfile: gemfiles/Gemfile.activerecord-4.2.x
|
23
|
+
rvm: 2.7.5
|
16
24
|
|
17
25
|
sudo: false
|
18
26
|
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
<p align="center">
|
2
2
|
<a href="https://github.com/mirego/activerecord_json_validator">
|
3
|
-
<img src="https://
|
3
|
+
<img src="https://user-images.githubusercontent.com/11348/126779905-3468eb15-d554-46d5-925b-235f68169d86.png" alt="" />
|
4
4
|
</a>
|
5
5
|
<br />
|
6
6
|
<code>ActiveRecord::JSONValidator</code> makes it easy to validate<br /> JSON attributes against a <a href="http://json-schema.org/">JSON schema</a>.
|
@@ -16,17 +16,19 @@
|
|
16
16
|
Add this line to your application's Gemfile:
|
17
17
|
|
18
18
|
```ruby
|
19
|
-
gem 'activerecord_json_validator'
|
19
|
+
gem 'activerecord_json_validator', '~> 2.0.0'
|
20
20
|
```
|
21
21
|
|
22
22
|
## Usage
|
23
23
|
|
24
24
|
### JSON Schema
|
25
25
|
|
26
|
+
Schemas should be a JSON file
|
27
|
+
|
26
28
|
```json
|
27
29
|
{
|
28
30
|
"type": "object",
|
29
|
-
"$schema": "http://json-schema.org/draft-04/schema",
|
31
|
+
"$schema": "http://json-schema.org/draft-04/schema#",
|
30
32
|
"properties": {
|
31
33
|
"city": { "type": "string" },
|
32
34
|
"country": { "type": "string" }
|
@@ -45,7 +47,7 @@ end
|
|
45
47
|
|
46
48
|
class User < ActiveRecord::Base
|
47
49
|
# Constants
|
48
|
-
PROFILE_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'profile.
|
50
|
+
PROFILE_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'profile.json')
|
49
51
|
|
50
52
|
# Validations
|
51
53
|
validates :name, presence: true
|
@@ -65,17 +67,16 @@ user.profile_invalid_json # => '{invalid JSON":}'
|
|
65
67
|
|
66
68
|
#### Options
|
67
69
|
|
68
|
-
| Option | Description
|
69
|
-
|
70
|
-
| `:schema` | The JSON schema to validate the data against (see **Schema** section)
|
71
|
-
| `:message` | The ActiveRecord message added to the record errors (see **Message** section)
|
72
|
-
| `:options` | A `Hash` of [`
|
70
|
+
| Option | Description |
|
71
|
+
| ---------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
72
|
+
| `:schema` | The JSON schema to validate the data against (see **Schema** section) |
|
73
|
+
| `:message` | The ActiveRecord message added to the record errors (see **Message** section) |
|
74
|
+
| `:options` | A `Hash` of [`json_schemer`](https://github.com/davishmcclurg/json_schemer#options)-supported options to pass to the validator |
|
73
75
|
|
74
76
|
##### Schema
|
75
77
|
|
76
|
-
`ActiveRecord::JSONValidator` uses the
|
77
|
-
data against a JSON schema.
|
78
|
-
`JSON::Validator.validate` would take as the `schema` argument.
|
78
|
+
`ActiveRecord::JSONValidator` uses the [json_schemer](https://github.com/davishmcclurg/json_schemer) gem to validate the JSON
|
79
|
+
data against a JSON schema.
|
79
80
|
|
80
81
|
Additionally, you can use a `Symbol` or a `Proc`. Both will be executed in the
|
81
82
|
context of the validated record (`Symbol` will be sent as a method and the
|
@@ -84,8 +85,8 @@ context of the validated record (`Symbol` will be sent as a method and the
|
|
84
85
|
```ruby
|
85
86
|
class User < ActiveRecord::Base
|
86
87
|
# Constants
|
87
|
-
PROFILE_REGULAR_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'profile.json_schema')
|
88
|
-
PROFILE_ADMIN_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'profile_admin.json_schema')
|
88
|
+
PROFILE_REGULAR_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'profile.json_schema')
|
89
|
+
PROFILE_ADMIN_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'profile_admin.json_schema')
|
89
90
|
|
90
91
|
# Validations
|
91
92
|
validates :profile, presence: true, json: { schema: lambda { dynamic_profile_schema } } # `schema: :dynamic_profile_schema` would also work
|
@@ -122,7 +123,7 @@ user.errors.full_messages
|
|
122
123
|
|
123
124
|
## License
|
124
125
|
|
125
|
-
`ActiveRecord::JSONValidator` is © 2013-2016 [Mirego](http://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause).
|
126
|
+
`ActiveRecord::JSONValidator` is © 2013-2016 [Mirego](http://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause). See the [`LICENSE.md`](https://github.com/mirego/activerecord_json_validator/blob/master/LICENSE.md) file.
|
126
127
|
|
127
128
|
The tree logo is based on [this lovely icon](http://thenounproject.com/term/tree/51004/) by [Sara Quintana](http://thenounproject.com/sara.quintana.75), from The Noun Project. Used under a [Creative Commons BY 3.0](http://creativecommons.org/licenses/by/3.0/) license.
|
128
129
|
|
@@ -18,15 +18,15 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_development_dependency 'bundler', '
|
21
|
+
spec.add_development_dependency 'bundler', '>= 1.12'
|
22
22
|
spec.add_development_dependency 'rake'
|
23
23
|
spec.add_development_dependency 'rspec', '~> 3.5'
|
24
24
|
spec.add_development_dependency 'pg'
|
25
25
|
spec.add_development_dependency 'mysql2'
|
26
|
-
spec.add_development_dependency 'activesupport', '>= 4.2.0', '<
|
26
|
+
spec.add_development_dependency 'activesupport', '>= 4.2.0', '< 8'
|
27
27
|
spec.add_development_dependency 'phare'
|
28
28
|
spec.add_development_dependency 'rubocop', '~> 0.28'
|
29
29
|
|
30
|
-
spec.add_dependency '
|
31
|
-
spec.add_dependency 'activerecord', '>= 4.2.0', '<
|
30
|
+
spec.add_dependency 'json_schemer', '~> 0.2.18'
|
31
|
+
spec.add_dependency 'activerecord', '>= 4.2.0', '< 8'
|
32
32
|
end
|
@@ -14,14 +14,15 @@ class JsonValidator < ActiveModel::EachValidator
|
|
14
14
|
|
15
15
|
# Validate the JSON value with a JSON schema path or String
|
16
16
|
def validate_each(record, attribute, value)
|
17
|
-
# Validate value with JSON
|
18
|
-
errors =
|
17
|
+
# Validate value with JSON Schemer
|
18
|
+
errors = JSONSchemer.schema(schema(record), **options.fetch(:options)).validate(value).to_a
|
19
19
|
|
20
20
|
# Everything is good if we don’t have any errors and we got valid JSON value
|
21
21
|
return if errors.empty? && record.send(:"#{attribute}_invalid_json").blank?
|
22
22
|
|
23
23
|
# Add error message to the attribute
|
24
24
|
message(errors).each do |error|
|
25
|
+
error = error.is_a?(Hash) ? JSONSchemer::Errors.pretty(error) : error
|
25
26
|
record.errors.add(attribute, error, value: value)
|
26
27
|
end
|
27
28
|
end
|
@@ -49,7 +50,7 @@ protected
|
|
49
50
|
end
|
50
51
|
end
|
51
52
|
|
52
|
-
# Return a valid schema
|
53
|
+
# Return a valid schema, recursively calling
|
53
54
|
# itself until it gets a non-Proc/non-Symbol value.
|
54
55
|
def schema(record, schema = nil)
|
55
56
|
schema ||= options.fetch(:schema)
|
@@ -61,12 +62,6 @@ protected
|
|
61
62
|
end
|
62
63
|
end
|
63
64
|
|
64
|
-
def validatable_value(value)
|
65
|
-
return value if value.is_a?(String)
|
66
|
-
|
67
|
-
::ActiveSupport::JSON.encode(value)
|
68
|
-
end
|
69
|
-
|
70
65
|
def message(errors)
|
71
66
|
message = options.fetch(:message)
|
72
67
|
|
data/spec/json_validator_spec.rb
CHANGED
@@ -4,105 +4,51 @@
|
|
4
4
|
require 'spec_helper'
|
5
5
|
|
6
6
|
describe JsonValidator do
|
7
|
-
describe :
|
8
|
-
# NOTE: We do not explicitely call `JsonValidator.new` in the tests,
|
9
|
-
# because we let Rails (ActiveModel::Validations) do that when we call
|
10
|
-
# `validates … json: true` on the model.
|
11
|
-
#
|
12
|
-
# This allows us to test the constructor behavior when executed in
|
13
|
-
# different Rails versions that do not pass the same arguments to it.
|
7
|
+
describe :validate_each do
|
14
8
|
before do
|
15
9
|
run_migration do
|
16
10
|
create_table(:users, force: true) do |t|
|
17
|
-
t.string :name
|
18
11
|
t.text :data
|
19
12
|
end
|
20
13
|
end
|
21
14
|
|
22
15
|
spawn_model 'User' do
|
16
|
+
schema = '
|
17
|
+
{
|
18
|
+
"type": "object",
|
19
|
+
"properties": {
|
20
|
+
"city": { "type": "string" },
|
21
|
+
"country": { "type": "string" }
|
22
|
+
},
|
23
|
+
"required": ["country"]
|
24
|
+
}
|
25
|
+
'
|
23
26
|
serialize :data, JSON
|
24
|
-
|
27
|
+
serialize :other_data, JSON
|
28
|
+
validates :data, json: { schema: schema, message: ->(errors) { errors } }
|
29
|
+
validates :other_data, json: { schema: schema, message: ->(errors) { errors.map { |error| error['details'].to_a.flatten.join(' ') } } }
|
25
30
|
end
|
26
|
-
|
27
|
-
record.data = data
|
28
|
-
end
|
29
|
-
|
30
|
-
let(:record) { User.new }
|
31
|
-
|
32
|
-
context 'with valid JSON data' do
|
33
|
-
let(:data) { 'What? This is not JSON at all.' }
|
34
|
-
it { expect(record.data_invalid_json).to eql(data) }
|
35
|
-
end
|
36
|
-
|
37
|
-
context 'with invalid JSON data' do
|
38
|
-
let(:data) { { foo: 'bar' } }
|
39
|
-
it { expect(record.data_invalid_json).to be_nil }
|
40
31
|
end
|
41
|
-
end
|
42
32
|
|
43
|
-
|
44
|
-
|
45
|
-
let(:options) { { attributes: [attribute], options: { strict: true } } }
|
46
|
-
let(:validate_each!) { validator.validate_each(record, attribute, value) }
|
47
|
-
|
48
|
-
# Doubles
|
49
|
-
let(:attribute) { double(:attribute, to_s: 'attribute_name') }
|
50
|
-
let(:record) { double(:record, errors: record_errors) }
|
51
|
-
let(:record_errors) { double(:errors) }
|
52
|
-
let(:value) { double(:value) }
|
53
|
-
let(:schema) { double(:schema) }
|
54
|
-
let(:validatable_value) { double(:validatable_value) }
|
55
|
-
let(:validator_errors) { double(:validator_errors) }
|
33
|
+
context 'with valid JSON data but schema errors' do
|
34
|
+
let(:user) { User.new(data: '{"city":"Quebec City"}', other_data: '{"city":"Quebec City"}') }
|
56
35
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
context 'with JSON::Validator errors' do
|
64
|
-
before do
|
65
|
-
expect(validator_errors).to receive(:empty?).and_return(false)
|
66
|
-
expect(record).not_to receive(:"#{attribute}_invalid_json")
|
67
|
-
expect(record_errors).to receive(:add).with(attribute, options[:message], value: value)
|
36
|
+
specify do
|
37
|
+
expect(user).not_to be_valid
|
38
|
+
expect(user.errors.full_messages).to eql(['Data root is missing required keys: country', 'Other data missing_keys country'])
|
39
|
+
expect(user.data).to eql({ 'city' => 'Quebec City' })
|
40
|
+
expect(user.data_invalid_json).to be_nil
|
68
41
|
end
|
69
|
-
|
70
|
-
specify { validate_each! }
|
71
42
|
end
|
72
43
|
|
73
|
-
context '
|
74
|
-
|
75
|
-
|
76
|
-
expect(record).to receive(:"#{attribute}_invalid_json").and_return('foo"{]')
|
77
|
-
expect(record_errors).to receive(:add).with(attribute, options[:message], value: value)
|
78
|
-
end
|
79
|
-
|
80
|
-
specify { validate_each! }
|
81
|
-
end
|
82
|
-
|
83
|
-
context 'without JSON::Validator errors and valid JSON data' do
|
84
|
-
before do
|
85
|
-
expect(validator_errors).to receive(:empty?).and_return(true)
|
86
|
-
expect(record).to receive(:"#{attribute}_invalid_json").and_return(nil)
|
87
|
-
expect(record_errors).not_to receive(:add)
|
88
|
-
end
|
89
|
-
|
90
|
-
specify { validate_each! }
|
91
|
-
end
|
92
|
-
|
93
|
-
context 'with multiple error messages' do
|
94
|
-
let(:options) { { attributes: [attribute], message: message, options: { strict: true } } }
|
95
|
-
let(:message) { ->(errors) { errors.to_a } }
|
44
|
+
context 'with invalid JSON data' do
|
45
|
+
let(:data) { 'What? This is not JSON at all.' }
|
46
|
+
let(:user) { User.new(data: data) }
|
96
47
|
|
97
|
-
|
98
|
-
expect(
|
99
|
-
expect(
|
100
|
-
expect(record).not_to receive(:"#{attribute}_invalid_json")
|
101
|
-
expect(record_errors).to receive(:add).with(attribute, :first_error, value: value)
|
102
|
-
expect(record_errors).to receive(:add).with(attribute, :second_error, value: value)
|
48
|
+
specify do
|
49
|
+
expect(user.data_invalid_json).to eql(data)
|
50
|
+
expect(user.data).to eql({})
|
103
51
|
end
|
104
|
-
|
105
|
-
specify { validate_each! }
|
106
52
|
end
|
107
53
|
end
|
108
54
|
|
@@ -155,22 +101,6 @@ describe JsonValidator do
|
|
155
101
|
end
|
156
102
|
end
|
157
103
|
|
158
|
-
describe :validatable_value do
|
159
|
-
let(:validator) { JsonValidator.new(options) }
|
160
|
-
let(:options) { { attributes: [:foo] } }
|
161
|
-
let(:validatable_value) { validator.send(:validatable_value, value) }
|
162
|
-
|
163
|
-
context 'with non-String value' do
|
164
|
-
let(:value) { { foo: 'bar' } }
|
165
|
-
it { expect(validatable_value).to eql('{"foo":"bar"}') }
|
166
|
-
end
|
167
|
-
|
168
|
-
context 'with String value' do
|
169
|
-
let(:value) { '{\"foo\":\"bar\"}' }
|
170
|
-
it { expect(validatable_value).to eql(value) }
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
104
|
describe :message do
|
175
105
|
let(:validator) { JsonValidator.new(options) }
|
176
106
|
let(:options) { { attributes: [:foo], message: message_option } }
|
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord_json_validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 2.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rémi Prévost
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.12'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.12'
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -89,7 +89,7 @@ dependencies:
|
|
89
89
|
version: 4.2.0
|
90
90
|
- - "<"
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version: '
|
92
|
+
version: '8'
|
93
93
|
type: :development
|
94
94
|
prerelease: false
|
95
95
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -99,7 +99,7 @@ dependencies:
|
|
99
99
|
version: 4.2.0
|
100
100
|
- - "<"
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: '
|
102
|
+
version: '8'
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: phare
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,19 +129,19 @@ dependencies:
|
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0.28'
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
|
-
name:
|
132
|
+
name: json_schemer
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
134
134
|
requirements:
|
135
135
|
- - "~>"
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version:
|
137
|
+
version: 0.2.18
|
138
138
|
type: :runtime
|
139
139
|
prerelease: false
|
140
140
|
version_requirements: !ruby/object:Gem::Requirement
|
141
141
|
requirements:
|
142
142
|
- - "~>"
|
143
143
|
- !ruby/object:Gem::Version
|
144
|
-
version:
|
144
|
+
version: 0.2.18
|
145
145
|
- !ruby/object:Gem::Dependency
|
146
146
|
name: activerecord
|
147
147
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,7 +151,7 @@ dependencies:
|
|
151
151
|
version: 4.2.0
|
152
152
|
- - "<"
|
153
153
|
- !ruby/object:Gem::Version
|
154
|
-
version: '
|
154
|
+
version: '8'
|
155
155
|
type: :runtime
|
156
156
|
prerelease: false
|
157
157
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -161,7 +161,7 @@ dependencies:
|
|
161
161
|
version: 4.2.0
|
162
162
|
- - "<"
|
163
163
|
- !ruby/object:Gem::Version
|
164
|
-
version: '
|
164
|
+
version: '8'
|
165
165
|
description: ActiveRecord::JSONValidator makes it easy to validate JSON attributes
|
166
166
|
with a JSON schema.
|
167
167
|
email:
|
@@ -182,6 +182,7 @@ files:
|
|
182
182
|
- gemfiles/Gemfile.activerecord-4.2.x
|
183
183
|
- gemfiles/Gemfile.activerecord-5.0.x
|
184
184
|
- gemfiles/Gemfile.activerecord-6.0.x
|
185
|
+
- gemfiles/Gemfile.activerecord-7.0.x
|
185
186
|
- lib/active_record/json_validator/validator.rb
|
186
187
|
- lib/active_record/json_validator/version.rb
|
187
188
|
- lib/activerecord_json_validator.rb
|
@@ -211,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
211
212
|
- !ruby/object:Gem::Version
|
212
213
|
version: '0'
|
213
214
|
requirements: []
|
214
|
-
rubygems_version: 3.
|
215
|
+
rubygems_version: 3.1.6
|
215
216
|
signing_key:
|
216
217
|
specification_version: 4
|
217
218
|
summary: ActiveRecord::JSONValidator makes it easy to validate JSON attributes with
|