activerecord_json_validator 0.4.2 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a61f1c0fe63a28ef0a8959b9b42b6213f10b2272
4
- data.tar.gz: ed3d3daa9ca75775ff430ce38d9571f1c9903679
3
+ metadata.gz: e916b93c42c1f418b5138f0680f1f3c6da4caca6
4
+ data.tar.gz: 891634217d8bf1d6430a919500bc05e0559e058a
5
5
  SHA512:
6
- metadata.gz: b45bd69284796f7eaca82efb36c445184d35dd3c7c04229246ffbf4a6a21d485c075c8260f883b72193eea6472683430daefb9bec2a284e08eda99855913f7eb
7
- data.tar.gz: 91237f18346a8b3e7816996d3b9740428cccd9b89a8c5c1f6f9ec5c24faf312249be6f94ab87cee66dc79a114648892826dd4a96b1b61f27addacfa211286409
6
+ metadata.gz: dcb7b8ae91f3eca385eab1d8480b9ad60072c6f5ec9cf777565e5279db47946a17f8c280deae9972fdeec22e3e81caa7fc221dee89d19cc1a821b27d7729fd74
7
+ data.tar.gz: 3eeda53bedb220bd51ea5cacf5e476cb6875acb8ef83fc78222f74e436ca4c3d89cd119544c904edae98a53e76cddd643a339b5654a8335acbc4fd20872c9e77
@@ -29,5 +29,4 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  spec.add_dependency 'json-schema', '~> 2.5'
31
31
  spec.add_dependency 'activerecord', '>= 4.1.0', '< 5'
32
- spec.add_dependency 'multi_json', '~> 1.10'
33
32
  end
@@ -2,6 +2,7 @@ class JsonValidator < ActiveModel::EachValidator
2
2
  def initialize(options)
3
3
  options.reverse_merge!(message: :invalid_json)
4
4
  options.reverse_merge!(schema: nil)
5
+ options.reverse_merge!(options: {})
5
6
  @attributes = options[:attributes]
6
7
 
7
8
  super
@@ -22,18 +23,11 @@ class JsonValidator < ActiveModel::EachValidator
22
23
 
23
24
  # Validate the JSON value with a JSON schema path or String
24
25
  def validate_each(record, attribute, value)
25
- begin
26
- json_value = JSON.dump(value)
27
- rescue JSON::GeneratorError
28
- json_value = ''
29
- end
30
-
31
26
  # Validate value with JSON::Validator
32
- schema = fetch_schema_for_record(record)
33
- errors = ::JSON::Validator.fully_validate(schema, json_value)
27
+ errors = ::JSON::Validator.fully_validate(schema(record), validatable_value(value), options.fetch(:options))
34
28
 
35
29
  # 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?
30
+ return if errors.empty? && record.send(:"#{attribute}_invalid_json").blank?
37
31
 
38
32
  # Add error message to the attribute
39
33
  record.errors.add(attribute, options.fetch(:message), value: value)
@@ -42,7 +36,7 @@ class JsonValidator < ActiveModel::EachValidator
42
36
  protected
43
37
 
44
38
  # Redefine the setter method for the attributes, since we want to
45
- # catch any MultiJson::LoadError errors.
39
+ # catch JSON parsing errors.
46
40
  def inject_setter_method(klass, attributes)
47
41
  attributes.each do |attribute|
48
42
  klass.class_eval <<-RUBY, __FILE__, __LINE__ + 1
@@ -53,7 +47,7 @@ protected
53
47
  @#{attribute}_invalid_json = nil
54
48
  args = ::ActiveSupport::JSON.decode(args) if args.is_a?(::String)
55
49
  super(args)
56
- rescue MultiJson::LoadError, JSON::ParserError
50
+ rescue ActiveSupport::JSON.parse_error
57
51
  @#{attribute}_invalid_json = args
58
52
  super({})
59
53
  end
@@ -62,12 +56,15 @@ protected
62
56
  end
63
57
  end
64
58
 
65
- def fetch_schema_for_record(record)
59
+ def schema(record)
66
60
  schema = options.fetch(:schema)
67
61
  return schema unless schema.is_a?(Proc)
68
62
 
69
63
  record.instance_exec(&schema)
70
64
  end
71
- end
72
65
 
73
- JSONValidator = JsonValidator
66
+ def validatable_value(value)
67
+ return value if value.is_a?(String)
68
+ ::ActiveSupport::JSON.encode(value)
69
+ end
70
+ end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module JSONValidator
3
- VERSION = '0.4.2'
3
+ VERSION = '0.5'
4
4
  end
5
5
  end
@@ -1,6 +1,9 @@
1
1
  require 'active_record'
2
2
  require 'json-schema'
3
- require 'multi_json'
4
3
 
5
4
  require 'active_record/json_validator/version'
6
5
  require 'active_record/json_validator/validator'
6
+
7
+ # NOTE: In case `"JSON"` is treated as an acronym by `ActiveSupport::Inflector`,
8
+ # make `JSONValidator` available too.
9
+ JSONValidator = JsonValidator
@@ -1,100 +1,133 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JsonValidator do
4
- before do
5
- run_migration do
6
- create_table(:users, force: true) do |t|
7
- t.string :name
8
- t.text :profile
4
+ describe :initialize do
5
+ # NOTE: We do not explicitely call `JsonValidator.new` in the tests,
6
+ # because we let Rails (ActiveModel::Validations) do that when we call
7
+ # `validates … json: true` on the model.
8
+ #
9
+ # This allows us to test the constructor behavior when executed in
10
+ # different Rails versions that do not pass the same arguments to it.
11
+ before do
12
+ run_migration do
13
+ create_table(:users, force: true) do |t|
14
+ t.string :name
15
+ t.text :data
16
+ end
9
17
  end
10
- end
11
18
 
12
- json_schema = schema
13
- spawn_model :User do
14
- serialize :profile, JSON
15
- validates :name, presence: true
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
- }
19
+ spawn_model 'User' do
20
+ serialize :data, JSON
21
+ validates :data, json: true
27
22
  end
28
- end
29
- end
30
23
 
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
24
+ record.data = data
25
+ end
42
26
 
43
- context 'with blank JSON value' do
44
- let(:attributes) { { name: 'Samuel Garneau', profile: {} } }
45
- it { expect(user).to_not be_valid }
46
- end
27
+ let(:record) { User.new }
47
28
 
48
- context 'with invalid JSON value' do
49
- context 'as Ruby Hash' do
50
- let(:attributes) { { name: 'Samuel Garneau', profile: { city: 'Quebec City' } } }
51
- it { expect(user).to_not be_valid }
29
+ context 'with valid JSON data' do
30
+ let(:data) { 'What? This is not JSON at all.' }
31
+ it { expect(record.data_invalid_json).to eql(data) }
52
32
  end
53
33
 
54
- context 'as JSON string' do
55
- let(:attributes) { { name: 'Samuel Garneau', profile: '{ "city": "Quebec City" }' } }
56
- it { expect(user).to_not be_valid }
34
+ context 'with invalid JSON data' do
35
+ let(:data) { { foo: 'bar' } }
36
+ it { expect(record.data_invalid_json).to be_nil }
57
37
  end
58
38
  end
59
39
 
60
- context 'with valid JSON value' do
61
- context 'as Ruby Hash' do
62
- let(:attributes) { { name: 'Samuel Garneau', profile: { country: 'CA' } } }
63
- it { expect(user).to be_valid }
40
+ describe :validate_each do
41
+ let(:validator) { JsonValidator.new(options) }
42
+ let(:options) { { attributes: [attribute], options: { strict: true } } }
43
+ let(:validate_each!) { validator.validate_each(record, attribute, value) }
44
+
45
+ # Doubles
46
+ let(:attribute) { double(:attribute, to_s: 'attribute_name') }
47
+ let(:record) { double(:record, errors: record_errors) }
48
+ let(:record_errors) { double(:errors) }
49
+ let(:value) { double(:value) }
50
+ let(:schema) { double(:schema) }
51
+ let(:validatable_value) { double(:validatable_value) }
52
+ let(:validator_errors) { double(:validator_errors) }
53
+
54
+ before do
55
+ expect(validator).to receive(:schema).with(record).and_return(schema)
56
+ expect(validator).to receive(:validatable_value).with(value).and_return(validatable_value)
57
+ expect(::JSON::Validator).to receive(:fully_validate).with(schema, validatable_value, options[:options]).and_return(validator_errors)
64
58
  end
65
59
 
66
- context 'as JSON string' do
67
- let(:attributes) { { name: 'Samuel Garneau', profile: '{ "country": "CA" }' } }
68
- it { expect(user).to be_valid }
60
+ context 'with JSON::Validator errors' do
61
+ before do
62
+ expect(validator_errors).to receive(:empty?).and_return(false)
63
+ expect(record).not_to receive(:"#{attribute}_invalid_json")
64
+ expect(record_errors).to receive(:add).with(attribute, options[:message], value: value)
65
+ end
66
+
67
+ specify { validate_each! }
69
68
  end
70
- end
71
69
 
72
- context 'with malformed JSON string' do
73
- let(:attributes) { { name: 'Samuel Garneau', profile: 'foo:}bar' } }
70
+ context 'without JSON::Validator errors but with invalid JSON data' do
71
+ before do
72
+ expect(validator_errors).to receive(:empty?).and_return(true)
73
+ expect(record).to receive(:"#{attribute}_invalid_json").and_return('foo"{]')
74
+ expect(record_errors).to receive(:add).with(attribute, options[:message], value: value)
75
+ end
74
76
 
75
- specify do
76
- expect(user).to_not be_valid
77
- expect(user.profile).to eql({})
78
- expect(user.profile_invalid_json).to eql('foo:}bar')
77
+ specify { validate_each! }
78
+ end
79
+
80
+ context 'without JSON::Validator errors and valid JSON data' do
81
+ before do
82
+ expect(validator_errors).to receive(:empty?).and_return(true)
83
+ expect(record).to receive(:"#{attribute}_invalid_json").and_return(nil)
84
+ expect(record_errors).not_to receive(:add)
85
+ end
86
+
87
+ specify { validate_each! }
79
88
  end
80
89
  end
81
90
 
82
- context 'with lambda schema option' do
83
- # The dynamic schema makes `country` and `city` keys mandatory
84
- let(:schema) { -> { dynamic_json_schema } }
91
+ describe :schema do
92
+ let(:validator) { JsonValidator.new(options) }
93
+ let(:options) { { attributes: [:foo], schema: schema_option } }
94
+ let(:schema) { validator.send(:schema, record) }
95
+
96
+ context 'with non-Proc schema' do
97
+ let(:schema_option) { double(:schema) }
98
+ let(:record) { double(:record) }
85
99
 
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 }
100
+ it { expect(schema).to eql(schema_option) }
89
101
  end
90
102
 
91
- context 'with invalid JSON value' do
92
- let(:attributes) { { name: 'Samuel Garneau', profile: {} } }
93
- it { expect(user).not_to be_valid }
103
+ context 'with Proc schema' do
104
+ let(:schema_option) { -> { dynamic_schema } }
105
+ let(:record) { record_class.new }
106
+ let(:record_class) do
107
+ Class.new do
108
+ def dynamic_schema
109
+ :yay
110
+ end
111
+ end
112
+ end
113
+
114
+ it { expect(schema).to eql(:yay) }
94
115
  end
95
116
  end
96
117
 
97
- context 'with JSON inflection' do
98
- it { expect(JSONValidator).to equal(JsonValidator) }
118
+ describe :validatable_value do
119
+ let(:validator) { JsonValidator.new(options) }
120
+ let(:options) { { attributes: [:foo] } }
121
+ let(:validatable_value) { validator.send(:validatable_value, value) }
122
+
123
+ context 'with non-String value' do
124
+ let(:value) { { foo: 'bar' } }
125
+ it { expect(validatable_value).to eql('{"foo":"bar"}') }
126
+ end
127
+
128
+ context 'with String value' do
129
+ let(:value) { "{\"foo\":\"bar\"}" }
130
+ it { expect(validatable_value).to eql(value) }
131
+ end
99
132
  end
100
133
  end
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.2
4
+ version: '0.5'
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-29 00:00:00.000000000 Z
11
+ date: 2015-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -162,20 +162,6 @@ dependencies:
162
162
  - - "<"
163
163
  - !ruby/object:Gem::Version
164
164
  version: '5'
165
- - !ruby/object:Gem::Dependency
166
- name: multi_json
167
- requirement: !ruby/object:Gem::Requirement
168
- requirements:
169
- - - "~>"
170
- - !ruby/object:Gem::Version
171
- version: '1.10'
172
- type: :runtime
173
- prerelease: false
174
- version_requirements: !ruby/object:Gem::Requirement
175
- requirements:
176
- - - "~>"
177
- - !ruby/object:Gem::Version
178
- version: '1.10'
179
165
  description: ActiveRecord::JSONValidator makes it easy to validate JSON attributes
180
166
  with a JSON schema.
181
167
  email: