active_data 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.codeclimate.yml +13 -0
- data/.rubocop.yml +56 -0
- data/.rubocop_todo.yml +53 -0
- data/.rvmrc +1 -1
- data/.travis.yml +15 -2
- data/Appraisals +1 -1
- data/CHANGELOG.md +31 -0
- data/Guardfile +8 -8
- data/README.md +256 -0
- data/Rakefile +2 -4
- data/active_data.gemspec +8 -7
- data/gemfiles/rails.4.0.gemfile +1 -1
- data/gemfiles/rails.4.1.gemfile +1 -1
- data/gemfiles/rails.4.2.gemfile +1 -1
- data/gemfiles/rails.5.0.gemfile +1 -1
- data/gemfiles/rails.5.1.gemfile +14 -0
- data/lib/active_data/active_record/associations.rb +18 -13
- data/lib/active_data/active_record/nested_attributes.rb +8 -14
- data/lib/active_data/base.rb +13 -0
- data/lib/active_data/config.rb +4 -4
- data/lib/active_data/errors.rb +29 -13
- data/lib/active_data/extensions.rb +22 -21
- data/lib/active_data/model/associations/base.rb +22 -6
- data/lib/active_data/model/associations/embeds_any.rb +17 -0
- data/lib/active_data/model/associations/embeds_many.rb +29 -19
- data/lib/active_data/model/associations/embeds_one.rb +30 -26
- data/lib/active_data/model/associations/nested_attributes.rb +82 -50
- data/lib/active_data/model/associations/persistence_adapters/active_record/referenced_proxy.rb +31 -0
- data/lib/active_data/model/associations/persistence_adapters/active_record.rb +66 -0
- data/lib/active_data/model/associations/persistence_adapters/base.rb +53 -0
- data/lib/active_data/model/associations/references_any.rb +41 -0
- data/lib/active_data/model/associations/references_many.rb +51 -37
- data/lib/active_data/model/associations/references_one.rb +43 -41
- data/lib/active_data/model/associations/reflections/base.rb +19 -29
- data/lib/active_data/model/associations/reflections/embeds_any.rb +43 -0
- data/lib/active_data/model/associations/reflections/embeds_many.rb +3 -13
- data/lib/active_data/model/associations/reflections/embeds_one.rb +5 -37
- data/lib/active_data/model/associations/reflections/references_any.rb +62 -0
- data/lib/active_data/model/associations/reflections/references_many.rb +7 -7
- data/lib/active_data/model/associations/reflections/references_one.rb +9 -7
- data/lib/active_data/model/associations/reflections/singular.rb +35 -0
- data/lib/active_data/model/associations/validations.rb +2 -27
- data/lib/active_data/model/associations.rb +12 -10
- data/lib/active_data/model/attributes/attribute.rb +10 -10
- data/lib/active_data/model/attributes/base.rb +8 -7
- data/lib/active_data/model/attributes/localized.rb +4 -4
- data/lib/active_data/model/attributes/reference_many.rb +6 -8
- data/lib/active_data/model/attributes/reference_one.rb +17 -9
- data/lib/active_data/model/attributes/reflections/attribute.rb +2 -2
- data/lib/active_data/model/attributes/reflections/base.rb +8 -11
- data/lib/active_data/model/attributes/reflections/localized.rb +2 -2
- data/lib/active_data/model/attributes/reflections/reference_one.rb +11 -22
- data/lib/active_data/model/attributes/reflections/represents.rb +5 -6
- data/lib/active_data/model/attributes/represents.rb +6 -5
- data/lib/active_data/model/attributes.rb +33 -87
- data/lib/active_data/model/callbacks.rb +6 -7
- data/lib/active_data/model/conventions.rb +2 -0
- data/lib/active_data/model/dirty.rb +4 -4
- data/lib/active_data/model/lifecycle.rb +18 -20
- data/lib/active_data/model/localization.rb +5 -2
- data/lib/active_data/model/persistence.rb +2 -2
- data/lib/active_data/model/primary.rb +19 -14
- data/lib/active_data/model/representation.rb +81 -0
- data/lib/active_data/model/scopes.rb +22 -12
- data/lib/active_data/model/validations/associated.rb +3 -2
- data/lib/active_data/model/validations/nested.rb +6 -1
- data/lib/active_data/model/validations.rb +3 -3
- data/lib/active_data/model.rb +2 -1
- data/lib/active_data/undefined_class.rb +9 -0
- data/lib/active_data/version.rb +1 -1
- data/lib/active_data.rb +40 -17
- data/spec/lib/active_data/active_record/associations_spec.rb +107 -45
- data/spec/lib/active_data/active_record/nested_attributes_spec.rb +1 -2
- data/spec/lib/active_data/config_spec.rb +37 -15
- data/spec/lib/active_data/model/associations/embeds_many_spec.rb +475 -172
- data/spec/lib/active_data/model/associations/embeds_one_spec.rb +353 -96
- data/spec/lib/active_data/model/associations/nested_attributes_spec.rb +108 -12
- data/spec/lib/active_data/model/associations/persistence_adapters/active_record_spec.rb +58 -0
- data/spec/lib/active_data/model/associations/references_many_spec.rb +440 -64
- data/spec/lib/active_data/model/associations/references_one_spec.rb +347 -36
- data/spec/lib/active_data/model/associations/reflections/embeds_many_spec.rb +8 -7
- data/spec/lib/active_data/model/associations/reflections/embeds_one_spec.rb +7 -6
- data/spec/lib/active_data/model/associations/reflections/references_many_spec.rb +81 -33
- data/spec/lib/active_data/model/associations/reflections/references_one_spec.rb +116 -37
- data/spec/lib/active_data/model/associations/validations_spec.rb +27 -43
- data/spec/lib/active_data/model/associations_spec.rb +34 -25
- data/spec/lib/active_data/model/attributes/attribute_spec.rb +26 -23
- data/spec/lib/active_data/model/attributes/base_spec.rb +5 -6
- data/spec/lib/active_data/model/attributes/collection_spec.rb +7 -8
- data/spec/lib/active_data/model/attributes/dictionary_spec.rb +40 -33
- data/spec/lib/active_data/model/attributes/localized_spec.rb +27 -28
- data/spec/lib/active_data/model/attributes/reflections/attribute_spec.rb +6 -6
- data/spec/lib/active_data/model/attributes/represents_spec.rb +10 -78
- data/spec/lib/active_data/model/attributes_spec.rb +150 -45
- data/spec/lib/active_data/model/callbacks_spec.rb +69 -70
- data/spec/lib/active_data/model/conventions_spec.rb +0 -1
- data/spec/lib/active_data/model/dirty_spec.rb +22 -13
- data/spec/lib/active_data/model/lifecycle_spec.rb +49 -23
- data/spec/lib/active_data/model/persistence_spec.rb +5 -6
- data/spec/lib/active_data/model/representation_spec.rb +126 -0
- data/spec/lib/active_data/model/scopes_spec.rb +1 -3
- data/spec/lib/active_data/model/typecasting_spec.rb +6 -5
- data/spec/lib/active_data/model/validations/associated_spec.rb +26 -18
- data/spec/lib/active_data/model/validations/nested_spec.rb +89 -18
- data/spec/lib/active_data/model_spec.rb +1 -2
- data/spec/lib/active_data_spec.rb +0 -1
- data/spec/shared/nested_attribute_examples.rb +332 -0
- data/spec/spec_helper.rb +3 -0
- data/spec/support/model_helpers.rb +2 -2
- data/spec/support/muffle_helper.rb +7 -0
- metadata +52 -18
- data/lib/active_data/model/associations/collection/referenced.rb +0 -26
- data/lib/active_data/model/associations/reflections/reference_reflection.rb +0 -45
- data/spec/lib/active_data/model/nested_attributes.rb +0 -202
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
3
|
describe ActiveData::Model::Lifecycle do
|
@@ -11,7 +10,7 @@ describe ActiveData::Model::Lifecycle do
|
|
11
10
|
|
12
11
|
subject { User.new }
|
13
12
|
|
14
|
-
[
|
13
|
+
%i[save create update destroy].each do |action|
|
15
14
|
specify { expect { subject.public_send "_#{action}_performer=", '' }.to raise_error NoMethodError }
|
16
15
|
end
|
17
16
|
|
@@ -19,9 +18,9 @@ describe ActiveData::Model::Lifecycle do
|
|
19
18
|
let(:foo) { true }
|
20
19
|
|
21
20
|
specify { expect { subject.save { foo } }.to raise_error NameError }
|
22
|
-
specify { expect { subject.save { |
|
21
|
+
specify { expect { subject.save { |_| attributes } }.to raise_error NameError }
|
23
22
|
specify { expect(subject.save { attributes }).to eq(true) }
|
24
|
-
specify { expect(subject.save { |
|
23
|
+
specify { expect(subject.save { |_| foo }).to eq(true) }
|
25
24
|
end
|
26
25
|
|
27
26
|
context 'save' do
|
@@ -87,7 +86,7 @@ describe ActiveData::Model::Lifecycle do
|
|
87
86
|
|
88
87
|
attribute :actions, Array, default: []
|
89
88
|
|
90
|
-
def append
|
89
|
+
def append(action)
|
91
90
|
self.actions = actions + [action]
|
92
91
|
end
|
93
92
|
|
@@ -106,7 +105,7 @@ describe ActiveData::Model::Lifecycle do
|
|
106
105
|
subject.destroy
|
107
106
|
subject.destroy
|
108
107
|
subject.save
|
109
|
-
expect(subject.actions).to eq([
|
108
|
+
expect(subject.actions).to eq(%i[destroy create update destroy destroy create])
|
110
109
|
end
|
111
110
|
end
|
112
111
|
end
|
@@ -198,10 +197,14 @@ describe ActiveData::Model::Lifecycle do
|
|
198
197
|
specify { expect { subject.update({}) }.not_to change { subject.persisted? } }
|
199
198
|
specify { expect { subject.update!({}) }.to raise_error ActiveData::ValidationError }
|
200
199
|
|
201
|
-
specify
|
202
|
-
|
203
|
-
|
204
|
-
|
200
|
+
specify do
|
201
|
+
expect { subject.update(name: 'Jonny') }
|
202
|
+
.to change { Storage.storage.keys }.from([]).to([subject.id])
|
203
|
+
end
|
204
|
+
specify do
|
205
|
+
expect { subject.update!(name: 'Jonny') }
|
206
|
+
.to change { Storage.storage.keys }.from([]).to([subject.id])
|
207
|
+
end
|
205
208
|
end
|
206
209
|
|
207
210
|
describe '#update_attributes, #update_attributes!' do
|
@@ -213,10 +216,14 @@ describe ActiveData::Model::Lifecycle do
|
|
213
216
|
specify { expect { subject.update_attributes({}) }.not_to change { subject.persisted? } }
|
214
217
|
specify { expect { subject.update_attributes!({}) }.to raise_error ActiveData::ValidationError }
|
215
218
|
|
216
|
-
specify
|
217
|
-
|
218
|
-
|
219
|
-
|
219
|
+
specify do
|
220
|
+
expect { subject.update_attributes(name: 'Jonny') }
|
221
|
+
.to change { Storage.storage.keys }.from([]).to([subject.id])
|
222
|
+
end
|
223
|
+
specify do
|
224
|
+
expect { subject.update_attributes!(name: 'Jonny') }
|
225
|
+
.to change { Storage.storage.keys }.from([]).to([subject.id])
|
226
|
+
end
|
220
227
|
end
|
221
228
|
|
222
229
|
describe '#save, #save!' do
|
@@ -230,7 +237,10 @@ describe ActiveData::Model::Lifecycle do
|
|
230
237
|
specify { expect { subject.save! }.to raise_error ActiveData::ValidationError }
|
231
238
|
|
232
239
|
specify { expect { subject.save }.not_to change { subject.persisted? } }
|
233
|
-
specify
|
240
|
+
specify do
|
241
|
+
expect { muffle(ActiveData::ValidationError) { subject.save! } }
|
242
|
+
.not_to change { subject.persisted? }
|
243
|
+
end
|
234
244
|
end
|
235
245
|
|
236
246
|
context 'create' do
|
@@ -257,7 +267,10 @@ describe ActiveData::Model::Lifecycle do
|
|
257
267
|
specify { expect { subject.save! }.to raise_error ActiveData::ObjectNotSaved }
|
258
268
|
|
259
269
|
specify { expect { subject.save }.not_to change { subject.persisted? } }
|
260
|
-
specify
|
270
|
+
specify do
|
271
|
+
expect { muffle(ActiveData::ObjectNotSaved) { subject.save! } }
|
272
|
+
.not_to change { subject.persisted? }
|
273
|
+
end
|
261
274
|
end
|
262
275
|
end
|
263
276
|
|
@@ -273,10 +286,14 @@ describe ActiveData::Model::Lifecycle do
|
|
273
286
|
specify { expect { subject.save }.not_to change { subject.persisted? } }
|
274
287
|
specify { expect { subject.save! }.not_to change { subject.persisted? } }
|
275
288
|
|
276
|
-
specify
|
277
|
-
.
|
278
|
-
|
279
|
-
|
289
|
+
specify do
|
290
|
+
expect { subject.save }.to change { Storage.storage[subject.id] }
|
291
|
+
.from(hash_including(name: 'Jonny')).to(hash_including(name: 'Jimmy'))
|
292
|
+
end
|
293
|
+
specify do
|
294
|
+
expect { subject.save! }.to change { Storage.storage[subject.id] }
|
295
|
+
.from(hash_including(name: 'Jonny')).to(hash_including(name: 'Jimmy'))
|
296
|
+
end
|
280
297
|
|
281
298
|
context 'save failed' do
|
282
299
|
before { User.define_save { false } }
|
@@ -287,7 +304,10 @@ describe ActiveData::Model::Lifecycle do
|
|
287
304
|
specify { expect { subject.save! }.to raise_error ActiveData::ObjectNotSaved }
|
288
305
|
|
289
306
|
specify { expect { subject.save }.not_to change { subject.persisted? } }
|
290
|
-
specify
|
307
|
+
specify do
|
308
|
+
expect { muffle(ActiveData::ObjectNotSaved) { subject.save! } }
|
309
|
+
.not_to change { subject.persisted? }
|
310
|
+
end
|
291
311
|
end
|
292
312
|
end
|
293
313
|
end
|
@@ -320,10 +340,16 @@ describe ActiveData::Model::Lifecycle do
|
|
320
340
|
specify { expect { subject.destroy! }.to raise_error ActiveData::ObjectNotDestroyed }
|
321
341
|
|
322
342
|
specify { expect { subject.destroy }.not_to change { subject.persisted? } }
|
323
|
-
specify
|
343
|
+
specify do
|
344
|
+
expect { muffle(ActiveData::ObjectNotDestroyed) { subject.destroy! } }
|
345
|
+
.not_to change { subject.persisted? }
|
346
|
+
end
|
324
347
|
|
325
348
|
specify { expect { subject.destroy }.not_to change { subject.destroyed? } }
|
326
|
-
specify
|
349
|
+
specify do
|
350
|
+
expect { muffle(ActiveData::ObjectNotDestroyed) { subject.destroy! } }
|
351
|
+
.not_to change { subject.destroyed? }
|
352
|
+
end
|
327
353
|
end
|
328
354
|
end
|
329
355
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
3
|
describe ActiveData::Model::Persistence do
|
@@ -22,7 +21,7 @@ describe ActiveData::Model::Persistence do
|
|
22
21
|
context do
|
23
22
|
subject(:instance) { model.instantiate(name: 'Hello', foo: 'Bar') }
|
24
23
|
|
25
|
-
specify { expect(subject.instance_variable_get(:@initial_attributes)).to eq({
|
24
|
+
specify { expect(subject.instance_variable_get(:@initial_attributes)).to eq({name: 'Hello'}.stringify_keys) }
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
@@ -31,17 +30,17 @@ describe ActiveData::Model::Persistence do
|
|
31
30
|
subject(:instances) { model.instantiate_collection(name: 'Hello', foo: 'Bar') }
|
32
31
|
|
33
32
|
specify { expect(subject).to be_a Array }
|
34
|
-
specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({
|
33
|
+
specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({name: 'Hello'}.stringify_keys) }
|
35
34
|
end
|
36
35
|
|
37
36
|
context do
|
38
37
|
before { model.send(:include, ActiveData::Model::Scopes) }
|
39
|
-
subject(:instances) { model.instantiate_collection([{
|
38
|
+
subject(:instances) { model.instantiate_collection([{name: 'Hello', foo: 'Bar'}, {name: 'World'}]) }
|
40
39
|
|
41
40
|
specify { expect(subject).to be_a ActiveData::Model::Scopes::ScopeProxy }
|
42
41
|
specify { expect(subject.count).to eq(2) }
|
43
|
-
specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({
|
44
|
-
specify { expect(subject.second.instance_variable_get(:@initial_attributes)).to eq({
|
42
|
+
specify { expect(subject.first.instance_variable_get(:@initial_attributes)).to eq({name: 'Hello'}.stringify_keys) }
|
43
|
+
specify { expect(subject.second.instance_variable_get(:@initial_attributes)).to eq({name: 'World'}.stringify_keys) }
|
45
44
|
end
|
46
45
|
end
|
47
46
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveData::Model::Representation do
|
4
|
+
context 'integration' do
|
5
|
+
before do
|
6
|
+
stub_model(:author) do
|
7
|
+
attribute :rate, Integer
|
8
|
+
end
|
9
|
+
|
10
|
+
stub_model(:post) do
|
11
|
+
include ActiveData::Model::Representation
|
12
|
+
|
13
|
+
attribute :author, Object
|
14
|
+
alias_attribute :a, :author
|
15
|
+
represents :rate, of: :a
|
16
|
+
alias_attribute :r, :rate
|
17
|
+
end
|
18
|
+
end
|
19
|
+
let(:author) { Author.new(rate: '42') }
|
20
|
+
|
21
|
+
specify { expect(Post.reflect_on_attribute(:rate).reference).to eq('author') }
|
22
|
+
|
23
|
+
specify { expect(Post.new(author: author).rate).to eq(42) }
|
24
|
+
specify { expect(Post.new(author: author).rate_before_type_cast).to eq('42') }
|
25
|
+
specify { expect(Post.new(rate: '33', author: author).rate).to eq(33) }
|
26
|
+
specify { expect(Post.new(rate: '33', author: author).author.rate).to eq(33) }
|
27
|
+
specify { expect(Post.new(r: '33', author: author).rate).to eq(33) }
|
28
|
+
specify { expect(Post.new(r: '33', author: author).author.rate).to eq(33) }
|
29
|
+
specify { expect(Post.new(author: author).rate?).to eq(true) }
|
30
|
+
specify { expect(Post.new(rate: nil, author: author).rate?).to eq(false) }
|
31
|
+
|
32
|
+
specify { expect(Post.new.rate).to be_nil }
|
33
|
+
specify { expect(Post.new.rate_before_type_cast).to be_nil }
|
34
|
+
specify { expect { Post.new(rate: '33') }.to raise_error(NoMethodError) }
|
35
|
+
|
36
|
+
context 'ActionController::Parameters' do
|
37
|
+
let(:params) { instance_double('ActionController::Parameters', to_unsafe_hash: {rate: '33', author: author}) }
|
38
|
+
specify { expect { Post.new(params) }.not_to raise_error }
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'dirty' do
|
42
|
+
before { Post.include ActiveData::Model::Dirty }
|
43
|
+
|
44
|
+
specify do
|
45
|
+
expect(Post.new(author: author, rate: '33').changes)
|
46
|
+
.to eq('author' => [nil, author], 'rate' => [42, 33])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context do
|
51
|
+
before do
|
52
|
+
stub_class(:author, ActiveRecord::Base)
|
53
|
+
|
54
|
+
stub_model(:post) do
|
55
|
+
include ActiveData::Model::Associations
|
56
|
+
include ActiveData::Model::Representation
|
57
|
+
|
58
|
+
references_one :author
|
59
|
+
alias_association :a, :author
|
60
|
+
represents :name, of: :a
|
61
|
+
end
|
62
|
+
end
|
63
|
+
let!(:author) { Author.create!(name: 42) }
|
64
|
+
|
65
|
+
specify { expect(Post.reflect_on_attribute(:name).reference).to eq('author') }
|
66
|
+
|
67
|
+
specify { expect(Post.new(name: '33', author: author).name).to eq('33') }
|
68
|
+
specify { expect(Post.new(name: '33', author: author).author.name).to eq('33') }
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'multiple attributes in a single represents definition' do
|
72
|
+
before do
|
73
|
+
stub_model(:author) do
|
74
|
+
attribute :first_name, String
|
75
|
+
attribute :last_name, String
|
76
|
+
end
|
77
|
+
|
78
|
+
stub_model(:post) do
|
79
|
+
include ActiveData::Model::Representation
|
80
|
+
|
81
|
+
attribute :author, Object
|
82
|
+
represents :first_name, :last_name, of: :author
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
let(:author) { Author.new(first_name: 'John', last_name: 'Doe') }
|
87
|
+
let(:post) { Post.new }
|
88
|
+
|
89
|
+
specify do
|
90
|
+
expect { post.update(author: author) }
|
91
|
+
.to change { post.first_name }.to('John')
|
92
|
+
.and change { post.last_name }.to('Doe')
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#validate' do
|
98
|
+
before do
|
99
|
+
stub_class(:author, ActiveRecord::Base) do
|
100
|
+
validates :name, presence: true
|
101
|
+
|
102
|
+
# Emulate Active Record association auto save error.
|
103
|
+
def errors
|
104
|
+
super.tap do |errors|
|
105
|
+
errors.add(:'user.email', 'is invalid') if errors[:'user.email'].empty?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
stub_model(:post) do
|
111
|
+
include ActiveData::Model::Associations
|
112
|
+
include ActiveData::Model::Representation
|
113
|
+
|
114
|
+
references_one :author
|
115
|
+
represents :name, :email, of: :author
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
let(:post) { Post.new(author: Author.new) }
|
120
|
+
|
121
|
+
specify do
|
122
|
+
expect { post.validate }.to change { post.errors.messages }
|
123
|
+
.to(hash_including(:'author.user.email' => ['is invalid'], name: ["can't be blank"]))
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
3
|
describe ActiveData::Model::Attributes do
|
@@ -96,10 +95,11 @@ describe ActiveData::Model::Attributes do
|
|
96
95
|
let(:model) { stub_model { attribute :column, Array } }
|
97
96
|
|
98
97
|
specify { expect(model.new(column: [1, 2, 3]).column).to eq([1, 2, 3]) }
|
99
|
-
specify { expect(model.new(column: 'hello, world').column).to eq([
|
98
|
+
specify { expect(model.new(column: 'hello, world').column).to eq(%w[hello world]) }
|
100
99
|
specify { expect(model.new(column: 10).column).to be_nil }
|
101
100
|
end
|
102
101
|
|
102
|
+
# rubocop:disable Style/DateTime
|
103
103
|
context 'date' do
|
104
104
|
let(:model) { stub_model { attribute :column, Date } }
|
105
105
|
let(:date) { Date.new(2013, 6, 13) }
|
@@ -149,6 +149,7 @@ describe ActiveData::Model::Attributes do
|
|
149
149
|
specify { expect(model.new(column: Time.new(2013, 6, 13, 23, 13)).column).to eq(Time.new(2013, 6, 13, 23, 13)) }
|
150
150
|
end
|
151
151
|
end
|
152
|
+
# rubocop:enable Style/DateTime
|
152
153
|
|
153
154
|
context 'time_zone' do
|
154
155
|
let(:model) { stub_model { attribute :column, ActiveSupport::TimeZone } }
|
@@ -175,13 +176,13 @@ describe ActiveData::Model::Attributes do
|
|
175
176
|
let(:uuid_tools) { UUIDTools::UUID.random_create }
|
176
177
|
|
177
178
|
specify { expect(uuid.as_json).to eq(uuid.to_s) }
|
178
|
-
specify { expect(uuid.to_json).to eq("\"#{uuid
|
179
|
+
specify { expect(uuid.to_json).to eq("\"#{uuid}\"") }
|
179
180
|
specify { expect(uuid.to_param).to eq(uuid.to_s) }
|
180
|
-
specify { expect(uuid.to_query(:key)).to eq("key=#{uuid
|
181
|
+
specify { expect(uuid.to_query(:key)).to eq("key=#{uuid}") }
|
181
182
|
|
182
183
|
specify { expect(model.new(column: nil).column).to be_nil }
|
183
184
|
specify { expect(model.new(column: Object.new).column).to be_nil }
|
184
|
-
specify { expect(model.new(column: uuid_tools).column).to be_a ActiveData::UUID
|
185
|
+
specify { expect(model.new(column: uuid_tools).column).to be_a ActiveData::UUID }
|
185
186
|
specify { expect(model.new(column: uuid_tools).column).to eq(uuid_tools) }
|
186
187
|
specify { expect(model.new(column: uuid).column).to eq(uuid) }
|
187
188
|
specify { expect(model.new(column: uuid.to_s).column).to eq(uuid) }
|
@@ -35,60 +35,68 @@ describe ActiveData::Model::Validations::AssociatedValidator do
|
|
35
35
|
end
|
36
36
|
|
37
37
|
context do
|
38
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_one: {
|
38
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_one: {name: 'name'} }
|
39
39
|
it { is_expected.to be_valid }
|
40
40
|
end
|
41
41
|
|
42
42
|
context do
|
43
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_one: {
|
43
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_one: {} }
|
44
44
|
it { is_expected.not_to be_valid }
|
45
|
-
specify
|
46
|
-
.to
|
45
|
+
specify do
|
46
|
+
expect { instance.validate }.to change { instance.errors.messages }
|
47
|
+
.to(validated_one: ['is invalid'])
|
48
|
+
end
|
47
49
|
end
|
48
50
|
|
49
51
|
context do
|
50
|
-
subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {
|
52
|
+
subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {name: 'name'} }
|
51
53
|
it { is_expected.to be_valid }
|
52
54
|
end
|
53
55
|
|
54
56
|
context do
|
55
|
-
subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {
|
57
|
+
subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {} }
|
56
58
|
it { is_expected.to be_valid }
|
57
59
|
end
|
58
60
|
|
59
61
|
context do
|
60
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{
|
62
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}] }
|
61
63
|
it { is_expected.to be_valid }
|
62
64
|
end
|
63
65
|
|
64
66
|
context do
|
65
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{
|
67
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}] }
|
66
68
|
it { is_expected.not_to be_valid }
|
67
|
-
specify
|
68
|
-
|
69
|
+
specify do
|
70
|
+
expect { instance.validate }.to change { instance.errors.messages }
|
71
|
+
.to(:'validated_many.0.name' => ["can't be blank"], validated_many: ['is invalid'])
|
72
|
+
end
|
69
73
|
end
|
70
74
|
|
71
75
|
context do
|
72
|
-
subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{
|
76
|
+
subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{name: 'name'}] }
|
73
77
|
it { is_expected.to be_valid }
|
74
78
|
end
|
75
79
|
|
76
80
|
context do
|
77
|
-
subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{
|
81
|
+
subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{}] }
|
78
82
|
it { is_expected.to be_valid }
|
79
83
|
end
|
80
84
|
|
81
85
|
context do
|
82
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{
|
86
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}], validated_one: {} }
|
83
87
|
it { is_expected.not_to be_valid }
|
84
|
-
specify
|
85
|
-
.to
|
88
|
+
specify do
|
89
|
+
expect { instance.validate }.to change { instance.errors.messages }
|
90
|
+
.to(validated_one: ['is invalid'])
|
91
|
+
end
|
86
92
|
end
|
87
93
|
|
88
94
|
context do
|
89
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{
|
95
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}], validated_one: {name: 'name'} }
|
90
96
|
it { is_expected.not_to be_valid }
|
91
|
-
specify
|
92
|
-
|
97
|
+
specify do
|
98
|
+
expect { instance.validate }.to change { instance.errors.messages }
|
99
|
+
.to(:'validated_many.0.name' => ["can't be blank"], validated_many: ['is invalid'])
|
100
|
+
end
|
93
101
|
end
|
94
102
|
end
|
@@ -5,7 +5,9 @@ describe ActiveData::Model::Validations::NestedValidator do
|
|
5
5
|
stub_model(:validated_assoc) do
|
6
6
|
include ActiveData::Model
|
7
7
|
include ActiveData::Model::Lifecycle
|
8
|
+
include ActiveData::Model::Primary
|
8
9
|
|
10
|
+
primary :id, Integer
|
9
11
|
attribute :name, String
|
10
12
|
|
11
13
|
validates_presence_of :name
|
@@ -34,60 +36,129 @@ describe ActiveData::Model::Validations::NestedValidator do
|
|
34
36
|
end
|
35
37
|
|
36
38
|
context do
|
37
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_one: {
|
39
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_one: {name: 'name'} }
|
38
40
|
it { is_expected.to be_valid }
|
39
41
|
end
|
40
42
|
|
41
43
|
context do
|
42
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_one: {
|
44
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_one: {} }
|
43
45
|
it { is_expected.not_to be_valid }
|
44
|
-
specify
|
45
|
-
.to
|
46
|
+
specify do
|
47
|
+
expect { instance.validate }.to change { instance.errors.messages }
|
48
|
+
.to(:'validated_one.name' => ["can't be blank"])
|
49
|
+
end
|
46
50
|
end
|
47
51
|
|
48
52
|
context do
|
49
|
-
subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {
|
53
|
+
subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {name: 'name'} }
|
50
54
|
it { is_expected.to be_valid }
|
51
55
|
end
|
52
56
|
|
53
57
|
context do
|
54
|
-
subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {
|
58
|
+
subject(:instance) { Main.instantiate name: 'hello', unvalidated_one: {} }
|
55
59
|
it { is_expected.to be_valid }
|
56
60
|
end
|
57
61
|
|
58
62
|
context do
|
59
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{
|
63
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}] }
|
60
64
|
it { is_expected.to be_valid }
|
61
65
|
end
|
62
66
|
|
63
67
|
context do
|
64
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{
|
68
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}] }
|
65
69
|
it { is_expected.not_to be_valid }
|
66
|
-
specify
|
67
|
-
.to
|
70
|
+
specify do
|
71
|
+
expect { instance.validate }.to change { instance.errors.messages }
|
72
|
+
.to(:'validated_many.0.name' => ["can't be blank"])
|
73
|
+
end
|
68
74
|
end
|
69
75
|
|
70
76
|
context do
|
71
|
-
subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{
|
77
|
+
subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{name: 'name'}] }
|
72
78
|
it { is_expected.to be_valid }
|
73
79
|
end
|
74
80
|
|
75
81
|
context do
|
76
|
-
subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{
|
82
|
+
subject(:instance) { Main.instantiate name: 'hello', unvalidated_many: [{}] }
|
77
83
|
it { is_expected.to be_valid }
|
78
84
|
end
|
79
85
|
|
80
86
|
context do
|
81
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{
|
87
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{name: 'name'}], validated_one: {} }
|
82
88
|
it { is_expected.not_to be_valid }
|
83
|
-
specify
|
84
|
-
.to
|
89
|
+
specify do
|
90
|
+
expect { instance.validate }.to change { instance.errors.messages }
|
91
|
+
.to(:'validated_one.name' => ["can't be blank"])
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'accepts nested attributes for one' do
|
96
|
+
before { Main.accepts_nested_attributes_for :validated_one, allow_destroy: true }
|
97
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_one: {id: 1, name: 'name'} }
|
98
|
+
|
99
|
+
specify do
|
100
|
+
instance.validated_one_attributes = {id: 1, name: '', _destroy: true}
|
101
|
+
is_expected.to be_valid
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'accepts nested attributes for many' do
|
106
|
+
before { Main.accepts_nested_attributes_for :validated_many, allow_destroy: true }
|
107
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{id: 1, name: 'name'}] }
|
108
|
+
|
109
|
+
specify do
|
110
|
+
instance.validated_many_attributes = [{id: 1, name: '', _destroy: true}]
|
111
|
+
is_expected.to be_valid
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'object field is invalid and referenced object does not include AutosaveAssociation' do
|
116
|
+
before do
|
117
|
+
stub_class(:validated_object) do
|
118
|
+
include ActiveData::Model::Validations
|
119
|
+
include ActiveData::Model::Attributes
|
120
|
+
include ActiveData::Model::Primary
|
121
|
+
|
122
|
+
primary :id
|
123
|
+
attribute :title, String
|
124
|
+
validates_presence_of :title
|
125
|
+
end
|
126
|
+
|
127
|
+
Main.class_eval do
|
128
|
+
include ActiveData::Model::Associations
|
129
|
+
attribute :object, Object
|
130
|
+
validates :object, nested: true
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
subject(:instance) { Main.instantiate name: 'hello', object: object, validated_one: {name: 'name'} }
|
135
|
+
|
136
|
+
context do
|
137
|
+
let(:object) { ValidatedObject.new(title: 'Mr.') }
|
138
|
+
it { is_expected.to be_valid }
|
139
|
+
end
|
140
|
+
|
141
|
+
context do
|
142
|
+
let(:object) { ValidatedObject.new }
|
143
|
+
it do
|
144
|
+
expect { subject.valid? }.not_to raise_error
|
145
|
+
expect(subject).not_to be_valid
|
146
|
+
end
|
147
|
+
end
|
85
148
|
end
|
86
149
|
|
87
150
|
context do
|
88
|
-
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{
|
151
|
+
subject(:instance) { Main.instantiate name: 'hello', validated_many: [{}], validated_one: {name: 'name'} }
|
89
152
|
it { is_expected.not_to be_valid }
|
90
|
-
specify
|
91
|
-
.to
|
153
|
+
specify do
|
154
|
+
expect { instance.validate }.to change { instance.errors.messages }
|
155
|
+
.to(:'validated_many.0.name' => ["can't be blank"])
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '.validates_nested?' do
|
160
|
+
specify { expect(Main).to be_validates_nested(:validated_one) }
|
161
|
+
specify { expect(Main).to be_validates_nested(:unvalidated_one) }
|
162
|
+
specify { expect(Main).not_to be_validates_nested(:something_else) }
|
92
163
|
end
|
93
164
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
require 'spec_helper'
|
3
2
|
|
4
3
|
describe ActiveData::Model do
|
@@ -6,6 +5,6 @@ describe ActiveData::Model do
|
|
6
5
|
specify { expect { model.blablabla }.to raise_error NoMethodError }
|
7
6
|
|
8
7
|
context 'Fault tolerance' do
|
9
|
-
specify{ expect { model.new(foo: 'bar') }.not_to raise_error }
|
8
|
+
specify { expect { model.new(foo: 'bar') }.not_to raise_error }
|
10
9
|
end
|
11
10
|
end
|