active_type 0.6.0 → 0.6.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/README.md +21 -0
- data/active_type.gemspec +1 -1
- data/gemfiles/Gemfile.3.2.mysql2.lock +1 -1
- data/gemfiles/Gemfile.3.2.sqlite3.lock +1 -1
- data/gemfiles/Gemfile.4.0.sqlite3.lock +1 -1
- data/gemfiles/Gemfile.4.1.sqlite3.lock +1 -1
- data/gemfiles/Gemfile.4.2.1.mysql2.lock +1 -1
- data/gemfiles/Gemfile.4.2.1.pg.lock +1 -1
- data/gemfiles/Gemfile.4.2.1.sqlite3.lock +1 -1
- data/gemfiles/Gemfile.5.0.0.mysql2.lock +1 -1
- data/gemfiles/Gemfile.5.0.0.pg.lock +1 -1
- data/gemfiles/Gemfile.5.0.0.sqlite3.lock +1 -1
- data/lib/active_type/version.rb +1 -1
- metadata +3 -53
- data/spec/active_type/extended_record/single_table_inheritance_spec.rb +0 -62
- data/spec/active_type/extended_record_spec.rb +0 -233
- data/spec/active_type/nested_attributes_spec.rb +0 -704
- data/spec/active_type/object_spec.rb +0 -463
- data/spec/active_type/record_spec.rb +0 -274
- data/spec/active_type/util_spec.rb +0 -142
- data/spec/integration/holidays_spec.rb +0 -102
- data/spec/integration/shape_spec.rb +0 -110
- data/spec/integration/sign_in_spec.rb +0 -101
- data/spec/integration/sign_up_spec.rb +0 -102
- data/spec/shared_examples/accessors.rb +0 -24
- data/spec/shared_examples/belongs_to.rb +0 -17
- data/spec/shared_examples/coercible_columns.rb +0 -248
- data/spec/shared_examples/constructor.rb +0 -30
- data/spec/shared_examples/defaults.rb +0 -60
- data/spec/shared_examples/dirty_tracking.rb +0 -40
- data/spec/shared_examples/dupable.rb +0 -31
- data/spec/shared_examples/mass_assignment.rb +0 -26
- data/spec/spec_helper.rb +0 -28
- data/spec/support/database.rb +0 -53
- data/spec/support/database.sample.yml +0 -3
- data/spec/support/error_on.rb +0 -12
- data/spec/support/i18n.rb +0 -1
- data/spec/support/protected_params.rb +0 -20
- data/spec/support/time_zone.rb +0 -1
@@ -1,704 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module NestedAttributesSpec
|
4
|
-
|
5
|
-
class Record < ActiveRecord::Base
|
6
|
-
attr_accessor :fail_on_save, :error
|
7
|
-
|
8
|
-
before_save :check_fail
|
9
|
-
|
10
|
-
validate :check_error
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def check_fail
|
15
|
-
if fail_on_save == true
|
16
|
-
if ActiveRecord::VERSION::MAJOR >= 5
|
17
|
-
throw :abort
|
18
|
-
else
|
19
|
-
false
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def check_error
|
25
|
-
if error.present?
|
26
|
-
errors.add(:base, error)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
32
|
-
|
33
|
-
class GlobalRecord < ActiveRecord::Base
|
34
|
-
self.table_name = 'records'
|
35
|
-
end
|
36
|
-
|
37
|
-
|
38
|
-
describe "ActiveType::Object" do
|
39
|
-
|
40
|
-
context '.nests_many' do
|
41
|
-
|
42
|
-
let(:extra_options) { {} }
|
43
|
-
|
44
|
-
subject do
|
45
|
-
extra = extra_options
|
46
|
-
Class.new(ActiveType::Object) do
|
47
|
-
nests_many :records, extra.merge(:scope => NestedAttributesSpec::Record)
|
48
|
-
|
49
|
-
def bad(attributes)
|
50
|
-
attributes[:persisted_string] =~ /bad/
|
51
|
-
end
|
52
|
-
|
53
|
-
def reject_all
|
54
|
-
true
|
55
|
-
end
|
56
|
-
|
57
|
-
end.new
|
58
|
-
end
|
59
|
-
|
60
|
-
def should_assign_and_persist(assign, persist = assign)
|
61
|
-
expect(subject.records.map(&:persisted_string)).to eq(assign)
|
62
|
-
expect(subject.save).to eq(true)
|
63
|
-
expect(NestedAttributesSpec::Record.all.map(&:persisted_string)).to match_array(persist)
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
context 'with no records assigned' do
|
68
|
-
|
69
|
-
it 'can save' do
|
70
|
-
expect(subject.save).to eq(true)
|
71
|
-
end
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
context 'assigning nil' do
|
76
|
-
|
77
|
-
it 'will do nothing' do
|
78
|
-
subject.records_attributes = nil
|
79
|
-
expect(subject.records).to be_nil
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
context 'when assigning records without ids' do
|
85
|
-
|
86
|
-
it 'builds single nested records' do
|
87
|
-
subject.records_attributes = { 1 => {:persisted_string => "string"} }
|
88
|
-
|
89
|
-
should_assign_and_persist(["string"])
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'builds multiple nested records when given a hash of attributes, ordered by key' do
|
93
|
-
subject.records_attributes = {
|
94
|
-
3 => {:persisted_string => "string 3"},
|
95
|
-
1 => {:persisted_string => "string 1"},
|
96
|
-
2 => {:persisted_string => "string 2"},
|
97
|
-
}
|
98
|
-
|
99
|
-
should_assign_and_persist(["string 1", "string 2", "string 3"])
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'builds multiple nested records when given an array of attributes' do
|
103
|
-
subject.records_attributes = [
|
104
|
-
{:persisted_string => "string 1"},
|
105
|
-
{:persisted_string => "string 2"},
|
106
|
-
{:persisted_string => "string 3"},
|
107
|
-
]
|
108
|
-
|
109
|
-
should_assign_and_persist(["string 1", "string 2", "string 3"])
|
110
|
-
end
|
111
|
-
|
112
|
-
it 'does not build records that match a :reject_if proc' do
|
113
|
-
extra_options.merge!(:reject_if => proc { |attributes| attributes['persisted_string'] =~ /bad/ })
|
114
|
-
subject.records_attributes = {
|
115
|
-
1 => {:persisted_string => "good value"},
|
116
|
-
2 => {:persisted_string => "bad value"},
|
117
|
-
}
|
118
|
-
|
119
|
-
should_assign_and_persist(["good value"])
|
120
|
-
end
|
121
|
-
|
122
|
-
it 'does not build records that match a :reject_if method taking attributes' do
|
123
|
-
extra_options.merge!(:reject_if => :bad)
|
124
|
-
subject.records_attributes = {
|
125
|
-
1 => {:persisted_string => "good value"},
|
126
|
-
2 => {:persisted_string => "bad value"},
|
127
|
-
}
|
128
|
-
|
129
|
-
should_assign_and_persist(["good value"])
|
130
|
-
end
|
131
|
-
|
132
|
-
it 'does not build records that match a :reject_if method taking attributes' do
|
133
|
-
extra_options.merge!(:reject_if => :bad)
|
134
|
-
subject.records_attributes = {
|
135
|
-
1 => {:persisted_string => "good value"},
|
136
|
-
2 => {:persisted_string => "bad value"},
|
137
|
-
}
|
138
|
-
|
139
|
-
should_assign_and_persist(["good value"])
|
140
|
-
end
|
141
|
-
|
142
|
-
it 'does not build records that match a :reject_if method taking no attributes' do
|
143
|
-
extra_options.merge!(:reject_if => :reject_all)
|
144
|
-
subject.records_attributes = {
|
145
|
-
1 => {:persisted_string => "good value"},
|
146
|
-
2 => {:persisted_string => "bad value"},
|
147
|
-
}
|
148
|
-
|
149
|
-
should_assign_and_persist([])
|
150
|
-
end
|
151
|
-
|
152
|
-
it 'does not build records that match a :reject_if all_blank' do
|
153
|
-
extra_options.merge!(:reject_if => :all_blank)
|
154
|
-
subject.records_attributes = {
|
155
|
-
1 => {:persisted_string => "good value"},
|
156
|
-
2 => {},
|
157
|
-
}
|
158
|
-
|
159
|
-
should_assign_and_persist(["good value"])
|
160
|
-
end
|
161
|
-
|
162
|
-
it 'appends to existing records' do
|
163
|
-
subject.records = [NestedAttributesSpec::Record.create!(:persisted_string => "existing string")]
|
164
|
-
subject.records_attributes = { 1 => {:persisted_string => "new string"} }
|
165
|
-
|
166
|
-
should_assign_and_persist(["existing string", "new string"])
|
167
|
-
end
|
168
|
-
|
169
|
-
it 'leaves unassigned records alone' do
|
170
|
-
NestedAttributesSpec::Record.create!(:persisted_string => "unassigned")
|
171
|
-
subject.records_attributes = { 1 => {:persisted_string => "string"} }
|
172
|
-
|
173
|
-
should_assign_and_persist(["string"], ["unassigned", "string"])
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'does not destroy records on _destroy => trueish by default' do
|
177
|
-
existing = NestedAttributesSpec::Record.create!(:persisted_string => 'do not delete this')
|
178
|
-
|
179
|
-
subject.records_attributes = [
|
180
|
-
{ :id => existing.id, :_destroy => "true" },
|
181
|
-
]
|
182
|
-
should_assign_and_persist(["do not delete this"], ["do not delete this"])
|
183
|
-
expect(subject.records.size).to eq(1)
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'destroys records on _destroy => trueish if allowed' do
|
187
|
-
extra_options.merge!(:allow_destroy => true)
|
188
|
-
existing = [
|
189
|
-
NestedAttributesSpec::Record.create!(:persisted_string => 'delete this'),
|
190
|
-
NestedAttributesSpec::Record.create!(:persisted_string => 'delete this'),
|
191
|
-
NestedAttributesSpec::Record.create!(:persisted_string => 'delete this'),
|
192
|
-
NestedAttributesSpec::Record.create!(:persisted_string => 'keep this'),
|
193
|
-
]
|
194
|
-
|
195
|
-
subject.records = existing.first(2) # assign some
|
196
|
-
|
197
|
-
subject.records_attributes = [
|
198
|
-
{ :id => existing[0].id, :_destroy => "true" },
|
199
|
-
{ :id => existing[1].id, :_destroy => 1 },
|
200
|
-
{ :id => existing[2].id, :_destroy => "1" },
|
201
|
-
{ :id => existing[3].id, :_destroy => "0" },
|
202
|
-
]
|
203
|
-
should_assign_and_persist(["delete this", "delete this", "delete this", "keep this"], ["keep this"])
|
204
|
-
expect(subject.records.size).to eq(1)
|
205
|
-
end
|
206
|
-
|
207
|
-
end
|
208
|
-
|
209
|
-
context 'when assigning records with ids' do
|
210
|
-
|
211
|
-
it 'updates the record with the id if already assigned' do
|
212
|
-
subject.records = [
|
213
|
-
NestedAttributesSpec::Record.new(:persisted_string => "existing 1"),
|
214
|
-
NestedAttributesSpec::Record.new(:persisted_string => "existing 2"),
|
215
|
-
NestedAttributesSpec::Record.new(:persisted_string => "existing 3"),
|
216
|
-
]
|
217
|
-
subject.records[0].id = 100
|
218
|
-
subject.records[1].id = 101
|
219
|
-
subject.records[2].id = 102
|
220
|
-
|
221
|
-
subject.records_attributes = { 1 => {:id => 101, :persisted_string => "updated"} }
|
222
|
-
|
223
|
-
should_assign_and_persist(["existing 1", "updated", "existing 3"])
|
224
|
-
end
|
225
|
-
|
226
|
-
it 'does not update records matching a reject_if proc' do
|
227
|
-
extra_options.merge!(:reject_if => :bad)
|
228
|
-
subject.records = [
|
229
|
-
NestedAttributesSpec::Record.new(:persisted_string => "existing 1"),
|
230
|
-
NestedAttributesSpec::Record.new(:persisted_string => "existing 2"),
|
231
|
-
]
|
232
|
-
subject.records[0].id = 100
|
233
|
-
subject.records[1].id = 101
|
234
|
-
|
235
|
-
subject.records_attributes = [
|
236
|
-
{:id => 100, :persisted_string => "good"},
|
237
|
-
{:id => 101, :persisted_string => "bad"}
|
238
|
-
]
|
239
|
-
|
240
|
-
should_assign_and_persist(["good", "existing 2"])
|
241
|
-
end
|
242
|
-
|
243
|
-
it 'fetches the record with the id if not already assigned' do
|
244
|
-
record = NestedAttributesSpec::Record.create!(:persisted_string => "existing string 1")
|
245
|
-
subject.records = [
|
246
|
-
NestedAttributesSpec::Record.new(:persisted_string => "existing string 2"),
|
247
|
-
]
|
248
|
-
subject.records[0].id = record.id + 1
|
249
|
-
|
250
|
-
subject.records_attributes = { 1 => {:id => record.id, :persisted_string => "updated string"} }
|
251
|
-
|
252
|
-
should_assign_and_persist(["existing string 2", "updated string"])
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'raises an error if the child record does not exist' do
|
256
|
-
expect do
|
257
|
-
subject.records_attributes = { 1 => {:id => 1, :persisted_string => "updated string"} }
|
258
|
-
end.to raise_error(ActiveType::NestedAttributes::RecordNotFound, "could not find a child record with id '1' for 'records'")
|
259
|
-
end
|
260
|
-
|
261
|
-
end
|
262
|
-
|
263
|
-
context 'save failure' do
|
264
|
-
|
265
|
-
it 'returns false on #save and does not save the child' do
|
266
|
-
# it should also cause a rollback, but that will not work with sqlite3
|
267
|
-
subject.records = [
|
268
|
-
NestedAttributesSpec::Record.new(:fail_on_save => true),
|
269
|
-
]
|
270
|
-
|
271
|
-
expect(subject.save).to be_falsey
|
272
|
-
expect(NestedAttributesSpec::Record.count).to eq(0)
|
273
|
-
|
274
|
-
# note that other children would be saved and not be rolled back
|
275
|
-
# this is also true for regular nested attributes
|
276
|
-
end
|
277
|
-
|
278
|
-
end
|
279
|
-
|
280
|
-
context 'validations' do
|
281
|
-
|
282
|
-
describe '#valid?' do
|
283
|
-
|
284
|
-
it 'is true if there are no records assigned' do
|
285
|
-
expect(subject.valid?).to eq(true)
|
286
|
-
end
|
287
|
-
|
288
|
-
it 'is true if all records are valid' do
|
289
|
-
subject.records = [
|
290
|
-
NestedAttributesSpec::Record.new,
|
291
|
-
NestedAttributesSpec::Record.new,
|
292
|
-
]
|
293
|
-
|
294
|
-
expect(subject.valid?).to eq(true)
|
295
|
-
end
|
296
|
-
|
297
|
-
it 'is false if one child has an error' do
|
298
|
-
subject.records = [
|
299
|
-
NestedAttributesSpec::Record.new,
|
300
|
-
NestedAttributesSpec::Record.new(:error => 'some error'),
|
301
|
-
]
|
302
|
-
|
303
|
-
expect(subject.valid?).to be_falsey
|
304
|
-
end
|
305
|
-
|
306
|
-
it 'is copies the error to the record' do
|
307
|
-
subject.records = [
|
308
|
-
NestedAttributesSpec::Record.new,
|
309
|
-
NestedAttributesSpec::Record.new(:error => 'some error'),
|
310
|
-
]
|
311
|
-
|
312
|
-
subject.valid?
|
313
|
-
expect(subject.errors["records.base"]).to eq(['some error'])
|
314
|
-
end
|
315
|
-
|
316
|
-
end
|
317
|
-
|
318
|
-
end
|
319
|
-
|
320
|
-
end
|
321
|
-
|
322
|
-
|
323
|
-
context '.nests_one' do
|
324
|
-
|
325
|
-
let(:extra_options) { {} }
|
326
|
-
|
327
|
-
subject do
|
328
|
-
extra = extra_options
|
329
|
-
Class.new(ActiveType::Object) do
|
330
|
-
nests_one :record, extra.merge(:scope => NestedAttributesSpec::Record)
|
331
|
-
|
332
|
-
def bad(attributes)
|
333
|
-
attributes[:persisted_string] =~ /bad/
|
334
|
-
end
|
335
|
-
end.new
|
336
|
-
end
|
337
|
-
|
338
|
-
def should_assign_and_persist(assign, persist = assign)
|
339
|
-
if assign
|
340
|
-
expect(subject.record).to be_present
|
341
|
-
expect(subject.record.persisted_string).to eq(assign)
|
342
|
-
else
|
343
|
-
expect(subject.record).to be_nil
|
344
|
-
end
|
345
|
-
expect(subject.save).to eq(true)
|
346
|
-
expect(NestedAttributesSpec::Record.all.map(&:persisted_string)).to eq(persist ? [persist] : [])
|
347
|
-
end
|
348
|
-
|
349
|
-
|
350
|
-
context 'with no record assigned' do
|
351
|
-
|
352
|
-
it 'can save' do
|
353
|
-
expect(subject.save).to eq(true)
|
354
|
-
end
|
355
|
-
|
356
|
-
end
|
357
|
-
|
358
|
-
context 'assigning nil' do
|
359
|
-
|
360
|
-
it 'will do nothing' do
|
361
|
-
subject.record_attributes = nil
|
362
|
-
expect(subject.record).to be_nil
|
363
|
-
end
|
364
|
-
|
365
|
-
end
|
366
|
-
|
367
|
-
context 'when assigning a records without an id' do
|
368
|
-
|
369
|
-
it 'builds a nested records' do
|
370
|
-
subject.record_attributes = { :persisted_string => "string" }
|
371
|
-
|
372
|
-
should_assign_and_persist("string")
|
373
|
-
end
|
374
|
-
|
375
|
-
it 'does not build a record that matchs a :reject_if proc' do
|
376
|
-
extra_options.merge!(:reject_if => proc { |attributes| attributes['persisted_string'] =~ /bad/ })
|
377
|
-
subject.record_attributes = { :persisted_string => "bad" }
|
378
|
-
|
379
|
-
should_assign_and_persist(nil)
|
380
|
-
end
|
381
|
-
|
382
|
-
|
383
|
-
it 'updates an assigned record' do
|
384
|
-
subject.record = NestedAttributesSpec::Record.create!(:persisted_string => "existing string")
|
385
|
-
subject.record_attributes = { :persisted_string => "new string" }
|
386
|
-
|
387
|
-
should_assign_and_persist("new string")
|
388
|
-
end
|
389
|
-
|
390
|
-
it 'does not update a record that matchs a :reject_if proc' do
|
391
|
-
extra_options.merge!(:reject_if => proc { |attributes| attributes['persisted_string'] =~ /bad/ })
|
392
|
-
subject.record = NestedAttributesSpec::Record.create!(:persisted_string => "existing string")
|
393
|
-
subject.record_attributes = { :persisted_string => "bad" }
|
394
|
-
|
395
|
-
should_assign_and_persist("existing string")
|
396
|
-
end
|
397
|
-
|
398
|
-
|
399
|
-
end
|
400
|
-
|
401
|
-
context 'when assigning a records with an id' do
|
402
|
-
|
403
|
-
let(:record) { record = NestedAttributesSpec::Record.create!(:persisted_string => "existing string") }
|
404
|
-
|
405
|
-
it 'updates the record if already assigned' do
|
406
|
-
subject.record = record
|
407
|
-
|
408
|
-
subject.record_attributes = { :id => record.id, :persisted_string => "updated string"}
|
409
|
-
|
410
|
-
should_assign_and_persist("updated string")
|
411
|
-
end
|
412
|
-
|
413
|
-
it 'fetches the record with the id if not already assigned' do
|
414
|
-
subject.record_attributes = { :id => record.id, :persisted_string => "updated string" }
|
415
|
-
|
416
|
-
should_assign_and_persist("updated string")
|
417
|
-
end
|
418
|
-
|
419
|
-
it 'does not destroy records on _destroy => true by default' do
|
420
|
-
subject.record_attributes = { :id => record.id, :_destroy => true }
|
421
|
-
|
422
|
-
should_assign_and_persist("existing string", "existing string")
|
423
|
-
end
|
424
|
-
|
425
|
-
it 'destroys records on _destroy => true if allowed' do
|
426
|
-
extra_options.merge!(:allow_destroy => true)
|
427
|
-
subject.record_attributes = { :id => record.id, :_destroy => true }
|
428
|
-
|
429
|
-
should_assign_and_persist("existing string", nil)
|
430
|
-
expect(subject.record).to eq(nil)
|
431
|
-
end
|
432
|
-
|
433
|
-
it 'raises an error if the assigned record does not match the id' do
|
434
|
-
expect do
|
435
|
-
subject.record = NestedAttributesSpec::Record.create!
|
436
|
-
subject.record_attributes = { :id => record.id, :persisted_string => "updated string" }
|
437
|
-
end.to raise_error(ActiveType::NestedAttributes::AssignmentError, "child record 'record' did not match id '#{record.id}'")
|
438
|
-
end
|
439
|
-
|
440
|
-
it 'raises an error if a record with the id cannot be found' do
|
441
|
-
expect do
|
442
|
-
subject.record_attributes = { :id => 1, :persisted_string => "updated string" }
|
443
|
-
end.to raise_error(ActiveType::NestedAttributes::RecordNotFound, "could not find a child record with id '1' for 'record'")
|
444
|
-
end
|
445
|
-
|
446
|
-
end
|
447
|
-
|
448
|
-
context 'validations' do
|
449
|
-
|
450
|
-
describe '#valid?' do
|
451
|
-
|
452
|
-
it 'is true if there is no record assigned' do
|
453
|
-
expect(subject.valid?).to eq(true)
|
454
|
-
end
|
455
|
-
|
456
|
-
it 'is true if the assigned record is valid' do
|
457
|
-
subject.record = NestedAttributesSpec::Record.new
|
458
|
-
|
459
|
-
expect(subject.valid?).to eq(true)
|
460
|
-
end
|
461
|
-
|
462
|
-
it 'is false the assigned record has an error' do
|
463
|
-
subject.record = NestedAttributesSpec::Record.new(:error => 'some error')
|
464
|
-
|
465
|
-
expect(subject.valid?).to be_falsey
|
466
|
-
end
|
467
|
-
|
468
|
-
it 'is copies the error to the record' do
|
469
|
-
subject.record = NestedAttributesSpec::Record.new(:error => 'some error')
|
470
|
-
|
471
|
-
subject.valid?
|
472
|
-
expect(subject.errors["record.base"]).to eq(['some error'])
|
473
|
-
end
|
474
|
-
|
475
|
-
end
|
476
|
-
|
477
|
-
end
|
478
|
-
|
479
|
-
end
|
480
|
-
|
481
|
-
context '.nests_one/nests_many' do
|
482
|
-
|
483
|
-
context 'inheritance' do
|
484
|
-
|
485
|
-
let(:base_class) do
|
486
|
-
Class.new(ActiveType::Object) do
|
487
|
-
nests_one :record, :scope => NestedAttributesSpec::Record
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
it 'works across inheritance hierarchy' do
|
492
|
-
subject = Class.new(base_class) do
|
493
|
-
nests_one :another_record, :scope => NestedAttributesSpec::Record
|
494
|
-
end.new
|
495
|
-
|
496
|
-
subject.record_attributes = { :persisted_string => "string" }
|
497
|
-
subject.another_record_attributes = {:persisted_string => "another string"}
|
498
|
-
|
499
|
-
expect(subject.record.persisted_string).to eq("string")
|
500
|
-
expect(subject.another_record.persisted_string).to eq("another string")
|
501
|
-
expect(subject.save).to eq(true)
|
502
|
-
expect(NestedAttributesSpec::Record.all.map(&:persisted_string)).to match_array(["string", "another string"])
|
503
|
-
end
|
504
|
-
|
505
|
-
it 'allows overriding of the accessor' do
|
506
|
-
subject = Class.new(base_class) do
|
507
|
-
def record_attributes=(attributes)
|
508
|
-
reached
|
509
|
-
super
|
510
|
-
end
|
511
|
-
|
512
|
-
def reached
|
513
|
-
end
|
514
|
-
end.new
|
515
|
-
|
516
|
-
expect(subject).to receive(:reached)
|
517
|
-
subject.record_attributes = { :persisted_string => "string" }
|
518
|
-
|
519
|
-
expect(subject.record.persisted_string).to eq("string")
|
520
|
-
expect(subject.save).to eq(true)
|
521
|
-
expect(NestedAttributesSpec::Record.all.map(&:persisted_string)).to match_array(["string"])
|
522
|
-
end
|
523
|
-
|
524
|
-
end
|
525
|
-
|
526
|
-
context 'when not giving a scope' do
|
527
|
-
|
528
|
-
subject do
|
529
|
-
Class.new(ActiveType::Object) do
|
530
|
-
nests_many :global_records
|
531
|
-
nests_one :global_record
|
532
|
-
end.new
|
533
|
-
end
|
534
|
-
|
535
|
-
it 'infers the scope from the association name' do
|
536
|
-
subject.global_records_attributes = { 1 => { :persisted_string => "string" } }
|
537
|
-
subject.global_record_attributes = { :persisted_string => "string" }
|
538
|
-
|
539
|
-
expect(subject.global_records.first).to be_a(GlobalRecord)
|
540
|
-
expect(subject.global_record).to be_a(GlobalRecord)
|
541
|
-
end
|
542
|
-
|
543
|
-
end
|
544
|
-
|
545
|
-
context 'when giving a scope via a proc' do
|
546
|
-
|
547
|
-
subject do
|
548
|
-
Class.new(ActiveType::Object) do
|
549
|
-
nests_many :records, :scope => proc { NestedAttributesSpec::Record.where("persisted_string <> 'invisible'") }
|
550
|
-
nests_one :record, :scope => proc { NestedAttributesSpec::Record }
|
551
|
-
|
552
|
-
attribute :default_value, :string
|
553
|
-
nests_many :default_records, :scope => proc { NestedAttributesSpec::Record.where(:persisted_string => default_value) }
|
554
|
-
end.new
|
555
|
-
end
|
556
|
-
|
557
|
-
it 'uses the scope' do
|
558
|
-
subject.records_attributes = { 1 => { :persisted_string => "string" } }
|
559
|
-
subject.record_attributes = { :persisted_string => "string" }
|
560
|
-
|
561
|
-
expect(subject.records.first).to be_a(NestedAttributesSpec::Record)
|
562
|
-
expect(subject.record).to be_a(NestedAttributesSpec::Record)
|
563
|
-
end
|
564
|
-
|
565
|
-
it 'evals the scope lazily in the instance' do
|
566
|
-
subject.default_value = "default value"
|
567
|
-
subject.default_records_attributes = [{}]
|
568
|
-
|
569
|
-
expect(subject.default_records.map(&:persisted_string)).to eq(["default value"])
|
570
|
-
end
|
571
|
-
|
572
|
-
it 'caches the scope' do
|
573
|
-
subject.default_value = "default value"
|
574
|
-
subject.default_records_attributes = [{}]
|
575
|
-
subject.default_value = "another default value"
|
576
|
-
subject.default_records_attributes = [{}]
|
577
|
-
|
578
|
-
expect(subject.default_records.map(&:persisted_string)).to eq(["default value", "default value"])
|
579
|
-
end
|
580
|
-
|
581
|
-
it 'caches the scope per instance' do
|
582
|
-
subject.default_value = "default value"
|
583
|
-
subject.default_records_attributes = [{}]
|
584
|
-
|
585
|
-
another_subject = subject.class.new
|
586
|
-
another_subject.default_value = "another default value"
|
587
|
-
another_subject.default_records_attributes = [{}]
|
588
|
-
|
589
|
-
expect(another_subject.default_records.map(&:persisted_string)).to eq(["another default value"])
|
590
|
-
end
|
591
|
-
|
592
|
-
it 'raises an error if the child record is not found via the scope' do
|
593
|
-
record = NestedAttributesSpec::Record.create!(:persisted_string => 'invisible')
|
594
|
-
|
595
|
-
expect do
|
596
|
-
subject.records_attributes = { 1 => { :id => record.id, :persisted_string => "updated string" } }
|
597
|
-
end.to raise_error(ActiveType::NestedAttributes::RecordNotFound, "could not find a child record with id '#{record.id}' for 'records'")
|
598
|
-
end
|
599
|
-
end
|
600
|
-
|
601
|
-
context 'separate scopes for build and find' do
|
602
|
-
|
603
|
-
subject do
|
604
|
-
find_scope = proc { NestedAttributesSpec::Record.where(:persisted_string => 'findable') }
|
605
|
-
build_scope = proc { NestedAttributesSpec::Record.where(:persisted_string => 'buildable') }
|
606
|
-
Class.new(ActiveType::Object) do
|
607
|
-
nests_many :records, :build_scope => build_scope, :find_scope => find_scope
|
608
|
-
nests_one :record, :build_scope => build_scope, :find_scope => find_scope
|
609
|
-
end.new
|
610
|
-
end
|
611
|
-
|
612
|
-
it 'nests_many uses the find_scope to find records' do
|
613
|
-
record = NestedAttributesSpec::Record.create!(:persisted_string => 'findable')
|
614
|
-
hidden_record = NestedAttributesSpec::Record.create!(:persisted_string => 'hidden')
|
615
|
-
|
616
|
-
expect do
|
617
|
-
subject.records_attributes = [{ :id => record.id, :persisted_string => 'updated' }]
|
618
|
-
end.to_not raise_error
|
619
|
-
|
620
|
-
expect do
|
621
|
-
subject.records_attributes = [{ :id => hidden_record.id, :persisted_string => 'updated' }]
|
622
|
-
end.to raise_error(ActiveType::NestedAttributes::RecordNotFound)
|
623
|
-
end
|
624
|
-
|
625
|
-
it 'nests_many uses the build_scope to find records' do
|
626
|
-
subject.records_attributes = [{}]
|
627
|
-
expect(subject.records.first.persisted_string).to eq('buildable')
|
628
|
-
end
|
629
|
-
|
630
|
-
it 'nests_one uses the find_scope to find records' do
|
631
|
-
record = NestedAttributesSpec::Record.create!(:persisted_string => 'findable')
|
632
|
-
hidden_record = NestedAttributesSpec::Record.create!(:persisted_string => 'hidden')
|
633
|
-
|
634
|
-
expect do
|
635
|
-
subject.record_attributes = { :id => record.id, :persisted_string => 'updated' }
|
636
|
-
end.to_not raise_error
|
637
|
-
|
638
|
-
subject.record = nil
|
639
|
-
expect do
|
640
|
-
subject.record_attributes = { :id => hidden_record.id, :persisted_string => 'updated' }
|
641
|
-
end.to raise_error(ActiveType::NestedAttributes::RecordNotFound)
|
642
|
-
end
|
643
|
-
|
644
|
-
it 'nests_one uses the build_scope to find records' do
|
645
|
-
subject.record_attributes = {}
|
646
|
-
expect(subject.record.persisted_string).to eq('buildable')
|
647
|
-
end
|
648
|
-
|
649
|
-
end
|
650
|
-
|
651
|
-
context 'defaults' do
|
652
|
-
|
653
|
-
subject do
|
654
|
-
Class.new(ActiveType::Object) do
|
655
|
-
nests_many :records, :default => proc { [default_record] }
|
656
|
-
nests_one :record, :default => proc { default_record }
|
657
|
-
|
658
|
-
nests_many :global_records
|
659
|
-
|
660
|
-
nests_many :other_records, :scope => proc { NestedAttributesSpec::Record }
|
661
|
-
nests_one :other_record, :scope => proc { NestedAttributesSpec::Record }
|
662
|
-
|
663
|
-
nests_many :records_without_default, :default => nil
|
664
|
-
|
665
|
-
def default_record
|
666
|
-
NestedAttributesSpec::Record.new(:persisted_string => "default")
|
667
|
-
end
|
668
|
-
end.new
|
669
|
-
end
|
670
|
-
|
671
|
-
it 'accepts a :default value' do
|
672
|
-
expect(subject.records.map(&:persisted_string)).to eq(["default"])
|
673
|
-
expect(subject.record.persisted_string).to eq("default")
|
674
|
-
end
|
675
|
-
|
676
|
-
it 'computes the value lazily' do
|
677
|
-
allow(subject).to receive_messages :default_record => NestedAttributesSpec::Record.new(:persisted_string => "other default")
|
678
|
-
expect(subject.records.map(&:persisted_string)).to eq(["other default"])
|
679
|
-
expect(subject.record.persisted_string).to eq("other default")
|
680
|
-
end
|
681
|
-
|
682
|
-
end
|
683
|
-
|
684
|
-
end
|
685
|
-
|
686
|
-
end
|
687
|
-
|
688
|
-
describe "ActiveType::Record" do
|
689
|
-
|
690
|
-
it 'supports nested attributes' do
|
691
|
-
expect(ActiveType::Record).to respond_to(:nests_one)
|
692
|
-
expect(ActiveType::Record).to respond_to(:nests_many)
|
693
|
-
end
|
694
|
-
|
695
|
-
end
|
696
|
-
|
697
|
-
describe "ActiveType::Record" do
|
698
|
-
|
699
|
-
it 'supports nested attributes' do
|
700
|
-
expect(ActiveType::Record[NestedAttributesSpec::Record]).to respond_to(:nests_one)
|
701
|
-
expect(ActiveType::Record[NestedAttributesSpec::Record]).to respond_to(:nests_many)
|
702
|
-
end
|
703
|
-
|
704
|
-
end
|