Skip to content

Commit 0f23927

Browse files
committed
Initial implementation of ValueObjects::ValidValidator to be used for validating ActiveModel attributes containing a value object or value object collection.
1 parent 3c32414 commit 0f23927

File tree

3 files changed

+182
-0
lines changed

3 files changed

+182
-0
lines changed

lib/value_objects.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
require 'active_record'
33
require 'value_objects/version'
44
require 'value_objects/value'
5+
require 'value_objects/valid_validator'

lib/value_objects/valid_validator.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
module ValueObjects
3+
4+
class ValidValidator < ActiveModel::EachValidator
5+
6+
def validate_each(record, attribute, value)
7+
record.errors.add(attribute, :invalid) unless value && (value.is_a?(Array) ? value.count(&:invalid?) == 0 : value.valid?)
8+
end
9+
10+
end
11+
12+
end
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
RSpec.describe ValueObjects::ValidValidator do
2+
3+
class NilAllowedRecord
4+
5+
include ActiveModel::Model
6+
include ActiveModel::Validations
7+
8+
attr_accessor :foo
9+
10+
validates :foo, 'value_objects/valid': true, allow_nil: true
11+
12+
end
13+
14+
class NilForbiddenRecord
15+
16+
include ActiveModel::Model
17+
include ActiveModel::Validations
18+
19+
attr_accessor :foo
20+
21+
validates :foo, 'value_objects/valid': true
22+
23+
end
24+
25+
context 'with allow_nil' do
26+
27+
let(:record) { NilAllowedRecord.new(foo: value) }
28+
29+
context 'and nil value' do
30+
31+
let(:value) { nil }
32+
33+
it 'passes validation' do
34+
aggregate_failures do
35+
expect(record.valid?).to eq(true)
36+
expect(record.errors).not_to include(:foo)
37+
end
38+
end
39+
40+
end
41+
42+
context 'and invalid value' do
43+
44+
let(:value) { instance_double('InvalidValue', valid?: false) }
45+
46+
it 'fails validation' do
47+
aggregate_failures do
48+
expect(record.valid?).to eq(false)
49+
expect(record.errors).to include(:foo)
50+
end
51+
end
52+
53+
end
54+
55+
context 'and valid value' do
56+
57+
let(:value) { instance_double('ValidValue', valid?: true) }
58+
59+
it 'passes validation' do
60+
aggregate_failures do
61+
expect(record.valid?).to eq(true)
62+
expect(record.errors).to be_empty
63+
end
64+
end
65+
66+
end
67+
68+
end
69+
70+
context 'without allow_nil' do
71+
72+
let(:validation_options) { { valid: true } }
73+
let(:record) { NilForbiddenRecord.new(foo: value) }
74+
75+
context 'and nil value' do
76+
77+
let(:value) { nil }
78+
79+
it 'fails validation' do
80+
aggregate_failures do
81+
expect(record.valid?).to eq(false)
82+
expect(record.errors).to include(:foo)
83+
end
84+
end
85+
86+
end
87+
88+
context 'and invalid value' do
89+
90+
let(:value) { instance_double('InvalidValue', valid?: false) }
91+
92+
it 'fails validation' do
93+
aggregate_failures do
94+
expect(record.valid?).to eq(false)
95+
expect(record.errors).to include(:foo)
96+
end
97+
end
98+
99+
end
100+
101+
context 'and valid value' do
102+
103+
let(:value) { instance_double('ValidValue', valid?: true) }
104+
105+
it 'passes validation' do
106+
aggregate_failures do
107+
expect(record.valid?).to eq(true)
108+
expect(record.errors).to be_empty
109+
end
110+
end
111+
112+
end
113+
114+
end
115+
116+
context 'with collection' do
117+
118+
let(:record) { NilForbiddenRecord.new(foo: values) }
119+
120+
context 'and no values' do
121+
122+
let(:values) { [] }
123+
124+
it 'passes validation' do
125+
aggregate_failures do
126+
expect(record.valid?).to eq(true)
127+
expect(record.errors).to be_empty
128+
end
129+
end
130+
131+
end
132+
133+
context 'and no invalid values' do
134+
135+
let(:values) { [value1, value2] }
136+
let(:value1) { instance_double('ValidValue') }
137+
let(:value2) { instance_double('ValidValue') }
138+
139+
it 'passes validation' do
140+
expect(value1).to receive(:invalid?).and_return(false).once
141+
expect(value2).to receive(:invalid?).and_return(false).once
142+
aggregate_failures do
143+
expect(record.valid?).to eq(true)
144+
expect(record.errors).to be_empty
145+
end
146+
end
147+
148+
end
149+
150+
context 'and some invalid values' do
151+
152+
let(:values) { [value1, value2] }
153+
let(:value1) { instance_double('ValidValue') }
154+
let(:value2) { instance_double('InvalidValue') }
155+
156+
it 'fails validation' do
157+
expect(value1).to receive(:invalid?).and_return(false).once
158+
expect(value2).to receive(:invalid?).and_return(true).once
159+
aggregate_failures do
160+
expect(record.valid?).to eq(false)
161+
expect(record.errors).to include(:foo)
162+
end
163+
end
164+
165+
end
166+
167+
end
168+
169+
end

0 commit comments

Comments
 (0)