activerecord_json_validator 0.3 → 0.4
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/.rubocop.yml +62 -0
- data/.travis.yml +3 -1
- data/README.md +80 -0
- data/Rakefile +1 -1
- data/activerecord_json_validator.gemspec +2 -0
- data/lib/active_record/json_validator/validator.rb +16 -5
- data/lib/active_record/json_validator/version.rb +1 -1
- data/spec/json_validator_spec.rb +39 -10
- data/spec/spec_helper.rb +1 -1
- data/spec/support/macros/database_macros.rb +1 -1
- metadata +31 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b48b4031de5f8c6acbebdf18140fcedba69ed87c
|
4
|
+
data.tar.gz: c378d6029f74ab611000db2ade4b785beec0f031
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 587e07e4a9fbb7dabc6e82dc880dd7069ee1eaf89b32f9523512d0d6e5ec5724e383f1e0301b2ef76c820b09a2370c59e7ed0e62d5fd4a919a2279b7ffda9e60
|
7
|
+
data.tar.gz: 6d8edfea72e360af096bf8abc94c8b9b56db6e4028f712e06488aa179a1dec59df06cf386bfe7bb986a779bba8ae3eabe67c552182c3cb59d0fab52046e59c9b
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- activerecord_json_validator.gemspec
|
4
|
+
|
5
|
+
Documentation:
|
6
|
+
Enabled: false
|
7
|
+
|
8
|
+
Encoding:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
LineLength:
|
12
|
+
Max: 200
|
13
|
+
|
14
|
+
AccessModifierIndentation:
|
15
|
+
EnforcedStyle: outdent
|
16
|
+
|
17
|
+
IfUnlessModifier:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
CaseIndentation:
|
21
|
+
IndentWhenRelativeTo: case
|
22
|
+
IndentOneStep: true
|
23
|
+
|
24
|
+
MethodLength:
|
25
|
+
CountComments: false
|
26
|
+
Max: 20
|
27
|
+
|
28
|
+
SignalException:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
ColonMethodCall:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
AsciiComments:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
RegexpLiteral:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
AssignmentInCondition:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
ParameterLists:
|
44
|
+
CountKeywordArgs: false
|
45
|
+
|
46
|
+
SingleLineBlockParams:
|
47
|
+
Methods:
|
48
|
+
- reduce:
|
49
|
+
- memo
|
50
|
+
- item
|
51
|
+
|
52
|
+
Metrics/AbcSize:
|
53
|
+
Enabled: false
|
54
|
+
|
55
|
+
Style/CollectionMethods:
|
56
|
+
Enabled: true
|
57
|
+
|
58
|
+
Style/SymbolArray:
|
59
|
+
Enabled: true
|
60
|
+
|
61
|
+
Style/ExtraSpacing:
|
62
|
+
Enabled: true
|
data/.travis.yml
CHANGED
@@ -18,7 +18,9 @@ before_script:
|
|
18
18
|
- mysql -e 'create database activerecord_json_validator_test;'
|
19
19
|
- psql -c 'create database activerecord_json_validator_test;' -U postgres
|
20
20
|
|
21
|
-
script:
|
21
|
+
script:
|
22
|
+
- 'echo "Checking code style" && bundle exec phare'
|
23
|
+
- 'echo "Running tests" && bundle exec rake spec'
|
22
24
|
|
23
25
|
addons:
|
24
26
|
postgresql: 9.3
|
data/README.md
CHANGED
@@ -56,6 +56,86 @@ user.valid? # => false
|
|
56
56
|
user.profile_invalid_json # => '{invalid JSON":}'
|
57
57
|
```
|
58
58
|
|
59
|
+
#### Options
|
60
|
+
|
61
|
+
| Option | Description
|
62
|
+
|------------|-----------------------------------------------------
|
63
|
+
| `:schema` | The JSON schema to validate the data against (see **JSON schema option** section)
|
64
|
+
| `:message` | The ActiveRecord message added to the record errors (default: `:invalid_json`)
|
65
|
+
|
66
|
+
##### JSON schema option
|
67
|
+
|
68
|
+
You can specify four kinds of value for the `:schema` option.
|
69
|
+
|
70
|
+
###### A path to a file containing a JSON schema
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class User < ActiveRecord::Base
|
74
|
+
# Constants
|
75
|
+
PROFILE_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'profile.json_schema').to_s
|
76
|
+
|
77
|
+
# Validations
|
78
|
+
validates :profile, presence: true, json: { schema: PROFILE_JSON_SCHEMA }
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
###### A Ruby `Hash` representing a JSON schema
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
class User < ActiveRecord::Base
|
86
|
+
# Constants
|
87
|
+
PROFILE_JSON_SCHEMA = {
|
88
|
+
type: 'object',
|
89
|
+
:'$schema' => 'http://json-schema.org/draft-03/schema',
|
90
|
+
properties: {
|
91
|
+
city: { type: 'string', required: false },
|
92
|
+
country: { type: 'string', required: true }
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
# Validations
|
97
|
+
validates :profile, presence: true, json: { schema: PROFILE_JSON_SCHEMA }
|
98
|
+
end
|
99
|
+
```
|
100
|
+
|
101
|
+
###### A plain JSON schema as a Ruby `String`
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
class User < ActiveRecord::Base
|
105
|
+
# Constants
|
106
|
+
PROFILE_JSON_SCHEMA = '{
|
107
|
+
"type": "object",
|
108
|
+
"$schema": "http://json-schema.org/draft-03/schema",
|
109
|
+
"properties": {
|
110
|
+
"city": { "type": "string", "required": false },
|
111
|
+
"country": { "type": "string", "required": true }
|
112
|
+
}
|
113
|
+
}'
|
114
|
+
|
115
|
+
# Validations
|
116
|
+
validates :profile, presence: true, json: { schema: PROFILE_JSON_SCHEMA }
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
###### A lambda that will get evaluated in the context of the validated record
|
121
|
+
|
122
|
+
The lambda must return a valid value for the `:schema` option (file path, JSON `String` or Ruby `Hash`).
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
class User < ActiveRecord::Base
|
126
|
+
# Constants
|
127
|
+
PROFILE_REGULAR_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'profile.json_schema').to_s
|
128
|
+
PROFILE_ADMIN_JSON_SCHEMA = Rails.root.join('config', 'schemas', 'profile_admin.json_schema').to_s
|
129
|
+
|
130
|
+
# Validations
|
131
|
+
validates :profile, presence: true, json: { schema: lambda { dynamic_profile_schema } }
|
132
|
+
|
133
|
+
def dynamic_profile_schema
|
134
|
+
admin? ? PROFILE_ADMIN_JSON_SCHEMA : PROFILE_REGULAR_JSON_SCHEMA
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
59
139
|
## License
|
60
140
|
|
61
141
|
`ActiveRecord::JSONValidator` is © 2013-2015 [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.
|
data/Rakefile
CHANGED
@@ -24,6 +24,8 @@ Gem::Specification.new do |spec|
|
|
24
24
|
spec.add_development_dependency 'pg'
|
25
25
|
spec.add_development_dependency 'mysql2'
|
26
26
|
spec.add_development_dependency 'activesupport', '>= 4.1.0', '< 5'
|
27
|
+
spec.add_development_dependency 'phare'
|
28
|
+
spec.add_development_dependency 'rubocop', '~> 0.28'
|
27
29
|
|
28
30
|
spec.add_dependency 'json-schema', '~> 2.5'
|
29
31
|
spec.add_dependency 'activerecord', '>= 4.1.0', '< 5'
|
@@ -28,11 +28,15 @@ class JsonValidator < ActiveModel::EachValidator
|
|
28
28
|
json_value = ''
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
# Validate value with JSON::Validator
|
32
|
+
schema = fetch_schema_for_record(record)
|
33
|
+
errors = ::JSON::Validator.fully_validate(schema, json_value)
|
32
34
|
|
33
|
-
if
|
34
|
-
|
35
|
-
|
35
|
+
# Everything is good if we don’t have any errors and we got valid JSON value
|
36
|
+
return true if errors.empty? && record.send(:"#{attribute}_invalid_json").blank?
|
37
|
+
|
38
|
+
# Add error message to the attribute
|
39
|
+
record.errors.add(attribute, options.fetch(:message), value: value)
|
36
40
|
end
|
37
41
|
|
38
42
|
protected
|
@@ -51,10 +55,17 @@ protected
|
|
51
55
|
super(args)
|
52
56
|
rescue MultiJson::LoadError, JSON::ParserError
|
53
57
|
@#{attribute}_invalid_json = args
|
54
|
-
super(
|
58
|
+
super({})
|
55
59
|
end
|
56
60
|
end
|
57
61
|
RUBY
|
58
62
|
end
|
59
63
|
end
|
64
|
+
|
65
|
+
def fetch_schema_for_record(record)
|
66
|
+
schema = options.fetch(:schema)
|
67
|
+
return schema unless schema.is_a?(Proc)
|
68
|
+
|
69
|
+
record.instance_exec(&schema)
|
70
|
+
end
|
60
71
|
end
|
data/spec/json_validator_spec.rb
CHANGED
@@ -9,23 +9,36 @@ describe JsonValidator do
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
json_schema = schema
|
12
13
|
spawn_model :User do
|
13
|
-
schema = {
|
14
|
-
type: 'object',
|
15
|
-
:'$schema' => 'http://json-schema.org/draft-03/schema',
|
16
|
-
properties: {
|
17
|
-
city: { type: 'string', required: false },
|
18
|
-
country: { type: 'string', required: true }
|
19
|
-
}
|
20
|
-
}
|
21
|
-
|
22
14
|
serialize :profile, JSON
|
23
15
|
validates :name, presence: true
|
24
|
-
validates :profile, presence: true, json: { schema:
|
16
|
+
validates :profile, presence: true, json: { schema: json_schema }
|
17
|
+
|
18
|
+
def dynamic_json_schema
|
19
|
+
{
|
20
|
+
type: 'object',
|
21
|
+
:'$schema' => 'http://json-schema.org/draft-03/schema',
|
22
|
+
properties: {
|
23
|
+
foo: { type: 'string', required: false },
|
24
|
+
bar: { type: 'string', required: true }
|
25
|
+
}
|
26
|
+
}
|
27
|
+
end
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
28
31
|
let(:user) { User.create(attributes) }
|
32
|
+
let(:schema) do
|
33
|
+
{
|
34
|
+
type: 'object',
|
35
|
+
:'$schema' => 'http://json-schema.org/draft-03/schema',
|
36
|
+
properties: {
|
37
|
+
city: { type: 'string', required: false },
|
38
|
+
country: { type: 'string', required: true }
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end
|
29
42
|
|
30
43
|
context 'with blank JSON value' do
|
31
44
|
let(:attributes) { { name: 'Samuel Garneau', profile: {} } }
|
@@ -61,7 +74,23 @@ describe JsonValidator do
|
|
61
74
|
|
62
75
|
specify do
|
63
76
|
expect(user).to_not be_valid
|
77
|
+
expect(user.profile).to eql({})
|
64
78
|
expect(user.profile_invalid_json).to eql('foo:}bar')
|
65
79
|
end
|
66
80
|
end
|
81
|
+
|
82
|
+
context 'with lambda schema option' do
|
83
|
+
# The dynamic schema makes `country` and `city` keys mandatory
|
84
|
+
let(:schema) { -> { dynamic_json_schema } }
|
85
|
+
|
86
|
+
context 'with valid JSON value' do
|
87
|
+
let(:attributes) { { name: 'Samuel Garneau', profile: { foo: 'bar', bar: 'foo' } } }
|
88
|
+
it { expect(user).to be_valid }
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'with invalid JSON value' do
|
92
|
+
let(:attributes) { { name: 'Samuel Garneau', profile: {} } }
|
93
|
+
it { expect(user).not_to be_valid }
|
94
|
+
end
|
95
|
+
end
|
67
96
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -5,7 +5,7 @@ module DatabaseMacros
|
|
5
5
|
klass = Class.new(ActiveRecord::Migration)
|
6
6
|
|
7
7
|
# Create a new `up` that executes the argument
|
8
|
-
klass.send(:define_method, :up) {
|
8
|
+
klass.send(:define_method, :up) { instance_exec(&block) }
|
9
9
|
|
10
10
|
# Create a new instance of it and execute its `up` method
|
11
11
|
klass.new.up
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord_json_validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.4'
|
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: 2015-01-
|
11
|
+
date: 2015-01-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -100,6 +100,34 @@ dependencies:
|
|
100
100
|
- - "<"
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: '5'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: phare
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: rubocop
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0.28'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - "~>"
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0.28'
|
103
131
|
- !ruby/object:Gem::Dependency
|
104
132
|
name: json-schema
|
105
133
|
requirement: !ruby/object:Gem::Requirement
|
@@ -158,6 +186,7 @@ extra_rdoc_files: []
|
|
158
186
|
files:
|
159
187
|
- ".gitignore"
|
160
188
|
- ".rspec"
|
189
|
+
- ".rubocop.yml"
|
161
190
|
- ".travis.yml"
|
162
191
|
- Gemfile
|
163
192
|
- LICENSE.md
|