granite-form 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -2
  3. data/.github/workflows/{ci.yml → ruby.yml} +22 -4
  4. data/.rubocop.yml +1 -1
  5. data/.rubocop_todo.yml +3 -3
  6. data/Appraisals +1 -2
  7. data/CHANGELOG.md +7 -0
  8. data/README.md +0 -2
  9. data/docker-compose.yml +14 -0
  10. data/gemfiles/rails.5.0.gemfile +0 -1
  11. data/gemfiles/rails.5.1.gemfile +0 -1
  12. data/gemfiles/rails.5.2.gemfile +0 -1
  13. data/granite-form.gemspec +15 -15
  14. data/lib/granite/form/active_record/associations.rb +1 -1
  15. data/lib/granite/form/base.rb +1 -2
  16. data/lib/granite/form/errors.rb +0 -15
  17. data/lib/granite/form/model/associations/base.rb +0 -4
  18. data/lib/granite/form/model/associations/collection/embedded.rb +2 -1
  19. data/lib/granite/form/model/associations/collection/proxy.rb +1 -1
  20. data/lib/granite/form/model/associations/embeds_any.rb +7 -0
  21. data/lib/granite/form/model/associations/embeds_many.rb +9 -58
  22. data/lib/granite/form/model/associations/embeds_one.rb +7 -36
  23. data/lib/granite/form/model/associations/nested_attributes.rb +5 -5
  24. data/lib/granite/form/model/associations/persistence_adapters/active_record.rb +0 -4
  25. data/lib/granite/form/model/associations/persistence_adapters/base.rb +0 -4
  26. data/lib/granite/form/model/associations/references_many.rb +0 -32
  27. data/lib/granite/form/model/associations/references_one.rb +0 -28
  28. data/lib/granite/form/model/associations/reflections/embeds_any.rb +1 -1
  29. data/lib/granite/form/model/associations/reflections/references_any.rb +0 -4
  30. data/lib/granite/form/model/associations/reflections/references_one.rb +0 -2
  31. data/lib/granite/form/model/associations/reflections/singular.rb +0 -8
  32. data/lib/granite/form/model/associations.rb +0 -6
  33. data/lib/granite/form/model/attributes/base.rb +1 -1
  34. data/lib/granite/form/model/attributes/reflections/attribute.rb +0 -6
  35. data/lib/granite/form/model/attributes/reflections/base.rb +8 -7
  36. data/lib/granite/form/model/attributes/reflections/reference_one.rb +0 -6
  37. data/lib/granite/form/model/persistence.rb +1 -19
  38. data/lib/granite/form/model.rb +0 -2
  39. data/lib/granite/form/version.rb +1 -1
  40. data/spec/granite/form/active_record/associations_spec.rb +16 -18
  41. data/spec/granite/form/model/associations/embeds_many_spec.rb +29 -305
  42. data/spec/granite/form/model/associations/embeds_one_spec.rb +27 -212
  43. data/spec/granite/form/model/associations/nested_attributes_spec.rb +0 -95
  44. data/spec/granite/form/model/associations/references_many_spec.rb +5 -326
  45. data/spec/granite/form/model/associations/references_one_spec.rb +6 -278
  46. data/spec/granite/form/model/associations/reflections/embeds_any_spec.rb +1 -2
  47. data/spec/granite/form/model/associations/reflections/embeds_many_spec.rb +18 -26
  48. data/spec/granite/form/model/associations/reflections/embeds_one_spec.rb +16 -23
  49. data/spec/granite/form/model/associations/reflections/references_many_spec.rb +1 -1
  50. data/spec/granite/form/model/associations/reflections/references_one_spec.rb +1 -22
  51. data/spec/granite/form/model/associations/validations_spec.rb +0 -3
  52. data/spec/granite/form/model/associations_spec.rb +3 -24
  53. data/spec/granite/form/model/dirty_spec.rb +1 -1
  54. data/spec/granite/form/model/persistence_spec.rb +0 -2
  55. data/spec/granite/form/model/validations/associated_spec.rb +2 -4
  56. data/spec/granite/form/model/validations/nested_spec.rb +2 -4
  57. data/spec/spec_helper.rb +0 -15
  58. data/spec/support/active_record.rb +20 -0
  59. data/spec/support/shared/nested_attribute_examples.rb +3 -21
  60. metadata +32 -38
  61. data/.github/workflows/main.yml +0 -29
  62. data/gemfiles/rails.4.2.gemfile +0 -15
  63. data/lib/granite/form/model/callbacks.rb +0 -72
  64. data/lib/granite/form/model/lifecycle.rb +0 -309
  65. data/spec/granite/form/model/callbacks_spec.rb +0 -337
  66. data/spec/granite/form/model/lifecycle_spec.rb +0 -356
@@ -7,7 +7,8 @@ describe Granite::Form::Model::Associations::EmbedsMany do
7
7
  end
8
8
 
9
9
  stub_model(:project) do
10
- include Granite::Form::Model::Lifecycle
10
+ include Granite::Form::Model::Persistence
11
+ include Granite::Form::Model::Associations
11
12
 
12
13
  attribute :title, String
13
14
  validates :title, presence: true
@@ -27,49 +28,6 @@ describe Granite::Form::Model::Associations::EmbedsMany do
27
28
  let(:existing_user) { User.instantiate name: 'Rick', projects: [{title: 'Genesis'}] }
28
29
  let(:existing_association) { existing_user.association(:projects) }
29
30
 
30
- context 'performers' do
31
- let(:user) { User.new(projects: [Project.new(title: 'Project 1')]) }
32
-
33
- specify do
34
- p2 = user.projects.build(title: 'Project 2')
35
- p3 = user.projects.build(title: 'Project 3')
36
- p4 = user.projects.create(title: 'Project 4')
37
- expect(user.read_attribute(:projects)).to eq([{'title' => 'Project 4'}])
38
- p2.save!
39
- expect(user.read_attribute(:projects)).to eq([{'title' => 'Project 2'}, {'title' => 'Project 4'}])
40
- p2.destroy!.destroy!
41
- expect(user.read_attribute(:projects)).to eq([{'title' => 'Project 4'}])
42
- user.projects.create(title: 'Project 5')
43
- expect(user.read_attribute(:projects)).to eq([{'title' => 'Project 4'}, {'title' => 'Project 5'}])
44
- p3.destroy!
45
- user.projects.first.destroy!
46
- expect(user.read_attribute(:projects)).to eq([{'title' => 'Project 4'}, {'title' => 'Project 5'}])
47
- p4.destroy!.save!
48
- expect(user.read_attribute(:projects)).to eq([{'title' => 'Project 4'}, {'title' => 'Project 5'}])
49
- expect(user.projects.count).to eq(5)
50
- user.projects.map(&:save!)
51
- expect(user.read_attribute(:projects)).to eq([
52
- {'title' => 'Project 1'}, {'title' => 'Project 2'}, {'title' => 'Project 3'},
53
- {'title' => 'Project 4'}, {'title' => 'Project 5'}
54
- ])
55
- user.projects.map(&:destroy!)
56
- expect(user.read_attribute(:projects)).to eq([])
57
- user.projects.first(2).map(&:save!)
58
- expect(user.read_attribute(:projects)).to eq([{'title' => 'Project 1'}, {'title' => 'Project 2'}])
59
- expect(user.projects.reload.count).to eq(2)
60
- p3 = user.projects.create!(title: 'Project 3')
61
- expect(user.read_attribute(:projects)).to eq([
62
- {'title' => 'Project 1'}, {'title' => 'Project 2'}, {'title' => 'Project 3'}
63
- ])
64
- p3.destroy!
65
- expect(user.read_attribute(:projects)).to eq([{'title' => 'Project 1'}, {'title' => 'Project 2'}])
66
- user.projects.create!(title: 'Project 4')
67
- expect(user.read_attribute(:projects)).to eq([
68
- {'title' => 'Project 1'}, {'title' => 'Project 2'}, {'title' => 'Project 4'}
69
- ])
70
- end
71
- end
72
-
73
31
  context 'callbacks' do
74
32
  before do
75
33
  User.class_eval do
@@ -101,24 +59,6 @@ describe Granite::Form::Model::Associations::EmbedsMany do
101
59
  ])
102
60
  end
103
61
 
104
- specify do
105
- expect { association.create(title: 'Project1') }
106
- .to change { user.callbacks }
107
- .to([[:before_add, project1], [:after_add, project1]])
108
- end
109
-
110
- specify do
111
- expect do
112
- association.create(title: 'Project1')
113
- association.create(title: 'Project2')
114
- end
115
- .to change { user.callbacks }
116
- .to([
117
- [:before_add, project1], [:after_add, project1],
118
- [:before_add, project2], [:after_add, project2]
119
- ])
120
- end
121
-
122
62
  specify do
123
63
  expect { association.concat(project1, project2) }
124
64
  .to change { user.callbacks }
@@ -194,7 +134,6 @@ describe Granite::Form::Model::Associations::EmbedsMany do
194
134
  let(:project) { Project.new(title: 'Project') }
195
135
 
196
136
  specify { expect(association.build.embedder).to eq(user) }
197
- specify { expect(association.create.embedder).to eq(user) }
198
137
  specify do
199
138
  expect { association.writer([project]) }
200
139
  .to change { project.embedder }.from(nil).to(user)
@@ -236,7 +175,6 @@ describe Granite::Form::Model::Associations::EmbedsMany do
236
175
  end
237
176
 
238
177
  specify { expect(association.build(title: 'Project').title).to eq('ProjectUser') }
239
- specify { expect(association.create(title: 'Project').title).to eq('ProjectUser') }
240
178
  end
241
179
  end
242
180
 
@@ -265,174 +203,6 @@ describe Granite::Form::Model::Associations::EmbedsMany do
265
203
  end
266
204
  end
267
205
 
268
- describe '#create' do
269
- specify { expect(association.create).to be_a Project }
270
- specify { expect(association.create).not_to be_persisted }
271
-
272
- specify { expect(association.create(title: 'Swordfish')).to be_a Project }
273
- specify { expect(association.create(title: 'Swordfish')).to be_persisted }
274
-
275
- specify do
276
- expect { association.create }
277
- .not_to change { user.read_attribute(:projects) }
278
- end
279
- specify do
280
- expect { association.create(title: 'Swordfish') }
281
- .to change { user.read_attribute(:projects) }
282
- .from(nil).to([{'title' => 'Swordfish'}])
283
- end
284
- specify do
285
- expect { association.create(title: 'Swordfish') }
286
- .to change { association.reader.map(&:attributes) }
287
- .from([]).to([{'title' => 'Swordfish'}])
288
- end
289
-
290
- specify do
291
- expect { existing_association.create }
292
- .not_to change { existing_user.read_attribute(:projects) }
293
- end
294
- specify do
295
- expect { existing_association.create(title: 'Swordfish') }
296
- .to change { existing_user.read_attribute(:projects) }
297
- .from([{title: 'Genesis'}]).to([{title: 'Genesis'}, {'title' => 'Swordfish'}])
298
- end
299
- specify do
300
- expect { existing_association.create(title: 'Swordfish') }
301
- .to change { existing_association.reader.map(&:attributes) }
302
- .from([{'title' => 'Genesis'}]).to([{'title' => 'Genesis'}, {'title' => 'Swordfish'}])
303
- end
304
- end
305
-
306
- describe '#create!' do
307
- specify { expect { association.create! }.to raise_error Granite::Form::ValidationError }
308
-
309
- specify { expect(association.create!(title: 'Swordfish')).to be_a Project }
310
- specify { expect(association.create!(title: 'Swordfish')).to be_persisted }
311
-
312
- specify do
313
- expect { muffle(Granite::Form::ValidationError) { association.create! } }
314
- .not_to change { user.read_attribute(:projects) }
315
- end
316
- specify do
317
- expect { muffle(Granite::Form::ValidationError) { association.create! } }
318
- .to change { association.reader.map(&:attributes) }.from([]).to([{'title' => nil}])
319
- end
320
- specify do
321
- expect { association.create!(title: 'Swordfish') }
322
- .to change { user.read_attribute(:projects) }.from(nil).to([{'title' => 'Swordfish'}])
323
- end
324
- specify do
325
- expect { association.create!(title: 'Swordfish') }
326
- .to change { association.reader.map(&:attributes) }
327
- .from([]).to([{'title' => 'Swordfish'}])
328
- end
329
-
330
- specify do
331
- expect { muffle(Granite::Form::ValidationError) { existing_association.create! } }
332
- .not_to change { existing_user.read_attribute(:projects) }
333
- end
334
- specify do
335
- expect { muffle(Granite::Form::ValidationError) { existing_association.create! } }
336
- .to change { existing_association.reader.map(&:attributes) }
337
- .from([{'title' => 'Genesis'}]).to([{'title' => 'Genesis'}, {'title' => nil}])
338
- end
339
- specify do
340
- expect { existing_association.create!(title: 'Swordfish') }
341
- .to change { existing_user.read_attribute(:projects) }
342
- .from([{title: 'Genesis'}]).to([{title: 'Genesis'}, {'title' => 'Swordfish'}])
343
- end
344
- specify do
345
- expect { existing_association.create!(title: 'Swordfish') }
346
- .to change { existing_association.reader.map(&:attributes) }
347
- .from([{'title' => 'Genesis'}]).to([{'title' => 'Genesis'}, {'title' => 'Swordfish'}])
348
- end
349
- end
350
-
351
- describe '#apply_changes' do
352
- specify do
353
- association.build
354
- expect { association.apply_changes }
355
- .not_to change { association.target.map(&:persisted?) }
356
- .from([false])
357
- end
358
- specify do
359
- association.build(title: 'Genesis')
360
- expect { association.apply_changes }
361
- .to change { association.target.map(&:persisted?) }
362
- .from([false]).to([true])
363
- end
364
- specify do
365
- existing_association.target.first.mark_for_destruction
366
- existing_association.build(title: 'Swordfish')
367
- expect { existing_association.apply_changes }
368
- .to change { existing_association.target.map(&:title) }
369
- .to(['Swordfish'])
370
- end
371
- specify do
372
- existing_association.target.first.mark_for_destruction
373
- existing_association.build(title: 'Swordfish')
374
- expect { existing_association.apply_changes }
375
- .to change { existing_association.target.map(&:persisted?) }
376
- .from([true, false]).to([true])
377
- end
378
- specify do
379
- existing_association.target.first.mark_for_destruction
380
- existing_association.build(title: 'Swordfish')
381
- expect { existing_association.apply_changes }
382
- .to change { existing_association.destroyed.map(&:title) }
383
- .from([]).to(['Genesis'])
384
- end
385
- specify do
386
- existing_association.target.first.destroy!
387
- existing_association.build(title: 'Swordfish')
388
- expect { existing_association.apply_changes }
389
- .to change { existing_association.target.map(&:title) }
390
- .to(['Swordfish'])
391
- end
392
- specify do
393
- existing_association.target.first.destroy!
394
- existing_association.build(title: 'Swordfish')
395
- expect { existing_association.apply_changes }
396
- .to change { existing_association.destroyed.map(&:title) }
397
- .from([]).to(['Genesis'])
398
- end
399
- end
400
-
401
- describe '#apply_changes!' do
402
- specify do
403
- association.build
404
- expect { association.apply_changes! }
405
- .to raise_error Granite::Form::AssociationChangesNotApplied
406
- end
407
- specify do
408
- association.build(title: 'Genesis')
409
- expect { association.apply_changes! }
410
- .to change { association.target.map(&:persisted?) }
411
- .to([true])
412
- end
413
- specify do
414
- existing_association.target.first.mark_for_destruction
415
- existing_association.build(title: 'Swordfish')
416
- expect { existing_association.apply_changes! }
417
- .to change { existing_association.target.map(&:title) }
418
- .to(['Swordfish'])
419
- end
420
- specify do
421
- existing_association.target.first.mark_for_destruction
422
- existing_association.build(title: 'Swordfish')
423
- expect { existing_association.apply_changes! }
424
- .to change { existing_association.target.map(&:persisted?) }
425
- .from([true, false]).to([true])
426
- end
427
- specify do
428
- existing_association.target.first.destroy!
429
- existing_association.build(title: 'Swordfish')
430
- expect { existing_association.apply_changes! }
431
- .to change { existing_association.target.map(&:title) }
432
- .to(['Swordfish'])
433
- end
434
- end
435
-
436
206
  describe '#target' do
437
207
  specify { expect(association.target).to eq([]) }
438
208
  specify { expect(existing_association.target).to eq(existing_user.projects) }
@@ -496,41 +266,44 @@ describe Granite::Form::Model::Associations::EmbedsMany do
496
266
  end
497
267
  end
498
268
 
499
- describe '#clear' do
500
- specify { expect(association.clear).to eq(true) }
501
- specify { expect { association.clear }.not_to change { association.reader } }
269
+ describe '#sync' do
270
+ let!(:project) { association.build(title: 'Genesis') }
502
271
 
503
- specify { expect(existing_association.clear).to eq(true) }
504
272
  specify do
505
- expect { existing_association.clear }
506
- .to change { existing_association.reader.map(&:attributes) }.from([{'title' => 'Genesis'}]).to([])
507
- end
508
- specify do
509
- expect { existing_association.clear }
510
- .to change { existing_user.read_attribute(:projects) }.from([{title: 'Genesis'}]).to([])
273
+ expect { association.sync }.to change { user.read_attribute(:projects) }.from(nil).to([{'title' => 'Genesis'}])
511
274
  end
512
275
 
513
- context do
514
- let(:existing_user) { User.instantiate name: 'Rick', projects: [{title: 'Genesis'}, {title: 'Swordfish'}] }
515
- before { Project.send(:include, Granite::Form::Model::Callbacks) }
516
- if ActiveModel.version >= Gem::Version.new('5.0.0')
517
- before { Project.before_destroy { throw :abort } }
518
- else
519
- before { Project.before_destroy { false } }
520
- end
276
+ context 'when embedding is nested' do
277
+ before do
278
+ Project.class_eval do
279
+ include Granite::Form::Model::Associations
521
280
 
522
- specify { expect(existing_association.clear).to eq(false) }
523
- specify do
524
- expect { existing_association.clear }
525
- .not_to change { existing_association.reader }
281
+ embeds_one :deadline do
282
+ attribute :enabled, Boolean
283
+ end
284
+ end
285
+
286
+ project.build_deadline(enabled: true)
526
287
  end
288
+
527
289
  specify do
528
- expect { existing_association.clear }
529
- .not_to change { existing_user.read_attribute(:projects) }
290
+ expect { association.sync }.to change { user.read_attribute(:projects) }
291
+ .from(nil).to([{'title' => 'Genesis', 'deadline' => {'enabled' => true}}])
530
292
  end
531
293
  end
532
294
  end
533
295
 
296
+ describe '#clear' do
297
+ specify { expect(association.clear).to eq(true) }
298
+ specify { expect { association.clear }.not_to change { association.reader } }
299
+
300
+ specify { expect(existing_association.clear).to eq(true) }
301
+ specify do
302
+ expect { existing_association.clear }
303
+ .to change { existing_association.reader.map(&:attributes) }.from([{'title' => 'Genesis'}]).to([])
304
+ end
305
+ end
306
+
534
307
  describe '#reader' do
535
308
  specify { expect(association.reader).to eq([]) }
536
309
 
@@ -573,52 +346,23 @@ describe Granite::Form::Model::Associations::EmbedsMany do
573
346
  expect { association.writer([new_project1]) }
574
347
  .to change { association.reader.map(&:attributes) }.from([]).to([{'title' => 'Project 1'}])
575
348
  end
576
- specify do
577
- expect { association.writer([new_project1]) }
578
- .not_to change { user.read_attribute(:projects) }
579
- end
580
-
581
- specify do
582
- expect { existing_association.writer([new_project1, invalid_project]) }
583
- .to raise_error Granite::Form::AssociationChangesNotApplied
584
- end
585
- specify do
586
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { existing_association.writer([new_project1, invalid_project]) } }
587
- .not_to change { existing_user.read_attribute(:projects) }
588
- end
589
- specify do
590
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { existing_association.writer([new_project1, invalid_project]) } }
591
- .not_to change { existing_association.reader }
592
- end
593
349
 
594
350
  specify do
595
351
  expect { existing_association.writer([new_project1, Dummy.new, new_project2]) }
596
352
  .to raise_error Granite::Form::AssociationTypeMismatch
597
353
  end
598
- specify do
599
- expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer([new_project1, Dummy.new, new_project2]) } }
600
- .not_to change { existing_user.read_attribute(:projects) }
601
- end
602
354
  specify do
603
355
  expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer([new_project1, Dummy.new, new_project2]) } }
604
356
  .not_to change { existing_association.reader }
605
357
  end
606
358
 
607
359
  specify { expect { existing_association.writer(nil) }.to raise_error NoMethodError }
608
- specify do
609
- expect { muffle(NoMethodError) { existing_association.writer(nil) } }
610
- .not_to change { existing_user.read_attribute(:projects) }
611
- end
612
360
  specify do
613
361
  expect { muffle(NoMethodError) { existing_association.writer(nil) } }
614
362
  .not_to change { existing_association.reader }
615
363
  end
616
364
 
617
365
  specify { expect(existing_association.writer([])).to eq([]) }
618
- specify do
619
- expect { existing_association.writer([]) }
620
- .to change { existing_user.read_attribute(:projects) }.to([])
621
- end
622
366
  specify do
623
367
  expect { existing_association.writer([]) }
624
368
  .to change { existing_association.reader }.to([])
@@ -630,11 +374,6 @@ describe Granite::Form::Model::Associations::EmbedsMany do
630
374
  .to change { existing_association.reader.map(&:attributes) }
631
375
  .from([{'title' => 'Genesis'}]).to([{'title' => 'Project 1'}, {'title' => 'Project 2'}])
632
376
  end
633
- specify do
634
- expect { existing_association.writer([new_project1, new_project2]) }
635
- .to change { existing_user.read_attribute(:projects) }
636
- .from([{title: 'Genesis'}]).to([{'title' => 'Project 1'}, {'title' => 'Project 2'}])
637
- end
638
377
  end
639
378
 
640
379
  describe '#concat' do
@@ -662,12 +401,6 @@ describe Granite::Form::Model::Associations::EmbedsMany do
662
401
  .not_to change { user.read_attribute(:projects) }
663
402
  end
664
403
 
665
- specify { expect(existing_association.concat(new_project1, invalid_project)).to eq(false) }
666
- specify do
667
- expect { existing_association.concat(new_project1, invalid_project) }
668
- .to change { existing_user.read_attribute(:projects) }
669
- .from([{title: 'Genesis'}]).to([{'title' => 'Genesis'}, {'title' => 'Project 1'}])
670
- end
671
404
  specify do
672
405
  expect { existing_association.concat(new_project1, invalid_project) }
673
406
  .to change { existing_association.reader.map(&:attributes) }
@@ -678,10 +411,6 @@ describe Granite::Form::Model::Associations::EmbedsMany do
678
411
  expect { existing_association.concat(new_project1, Dummy.new, new_project2) }
679
412
  .to raise_error Granite::Form::AssociationTypeMismatch
680
413
  end
681
- specify do
682
- expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.concat(new_project1, Dummy.new, new_project2) } }
683
- .not_to change { existing_user.read_attribute(:projects) }
684
- end
685
414
  specify do
686
415
  expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.concat(new_project1, Dummy.new, new_project2) } }
687
416
  .to change { existing_association.reader.map(&:attributes) }
@@ -697,10 +426,5 @@ describe Granite::Form::Model::Associations::EmbedsMany do
697
426
  .to change { existing_association.reader.map(&:attributes) }
698
427
  .from([{'title' => 'Genesis'}]).to([{'title' => 'Genesis'}, {'title' => 'Project 1'}, {'title' => 'Project 2'}])
699
428
  end
700
- specify do
701
- expect { existing_association.concat([new_project1, new_project2]) }
702
- .to change { existing_user.read_attribute(:projects) }
703
- .from([{title: 'Genesis'}]).to([{'title' => 'Genesis'}, {'title' => 'Project 1'}, {'title' => 'Project 2'}])
704
- end
705
429
  end
706
430
  end