granite-form 0.2.0 → 0.3.0

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.
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
@@ -3,7 +3,8 @@ require 'spec_helper'
3
3
  describe Granite::Form::Model::Associations::EmbedsOne do
4
4
  before do
5
5
  stub_model(:author) do
6
- include Granite::Form::Model::Lifecycle
6
+ include Granite::Form::Model::Persistence
7
+ include Granite::Form::Model::Associations
7
8
 
8
9
  attribute :name, String
9
10
  validates :name, presence: true
@@ -61,12 +62,6 @@ describe Granite::Form::Model::Associations::EmbedsOne do
61
62
  ])
62
63
  end
63
64
 
64
- specify do
65
- expect { association.create(name: 'Author1') }
66
- .to change { book.callbacks }
67
- .to([[:before_add, author1], [:after_add, author1]])
68
- end
69
-
70
65
  specify do
71
66
  expect { association.writer(author1) }
72
67
  .to change { book.callbacks }
@@ -118,7 +113,6 @@ describe Granite::Form::Model::Associations::EmbedsOne do
118
113
  let(:author) { Author.new(name: 'Author') }
119
114
 
120
115
  specify { expect(association.build.embedder).to eq(book) }
121
- specify { expect(association.create.embedder).to eq(book) }
122
116
  specify do
123
117
  expect { association.writer(author) }
124
118
  .to change { author.embedder }.from(nil).to(book)
@@ -156,7 +150,6 @@ describe Granite::Form::Model::Associations::EmbedsOne do
156
150
  end
157
151
 
158
152
  specify { expect(association.build(name: 'Author').name).to eq('AuthorBook') }
159
- specify { expect(association.create(name: 'Author').name).to eq('AuthorBook') }
160
153
  end
161
154
  end
162
155
 
@@ -175,132 +168,6 @@ describe Granite::Form::Model::Associations::EmbedsOne do
175
168
  end
176
169
  end
177
170
 
178
- describe '#create' do
179
- specify { expect(association.create).to be_a Author }
180
- specify { expect(association.create).not_to be_persisted }
181
-
182
- specify { expect(association.create(name: 'Fred')).to be_a Author }
183
- specify { expect(association.create(name: 'Fred')).to be_persisted }
184
-
185
- specify do
186
- expect { association.create }
187
- .not_to change { book.read_attribute(:author) }
188
- end
189
- specify do
190
- expect { association.create(name: 'Fred') }
191
- .to change { book.read_attribute(:author) }
192
- .from(nil).to('name' => 'Fred')
193
- end
194
-
195
- specify do
196
- expect { existing_association.create }
197
- .not_to change { existing_book.read_attribute(:author) }
198
- end
199
- specify do
200
- expect { existing_association.create(name: 'Fred') }
201
- .to change { existing_book.read_attribute(:author) }
202
- .from('name' => 'Johny').to('name' => 'Fred')
203
- end
204
- end
205
-
206
- describe '#create!' do
207
- specify { expect { association.create! }.to raise_error Granite::Form::ValidationError }
208
- specify do
209
- expect { muffle(Granite::Form::ValidationError) { association.create! } }
210
- .to change { association.target }
211
- .from(nil).to(an_instance_of(Author))
212
- end
213
-
214
- specify { expect(association.create!(name: 'Fred')).to be_a Author }
215
- specify { expect(association.create!(name: 'Fred')).to be_persisted }
216
-
217
- specify do
218
- expect { muffle(Granite::Form::ValidationError) { association.create! } }
219
- .not_to change { book.read_attribute(:author) }
220
- end
221
- specify do
222
- expect { muffle(Granite::Form::ValidationError) { association.create! } }
223
- .to change { association.reader.try(:attributes) }
224
- .from(nil).to('name' => nil)
225
- end
226
- specify do
227
- expect { association.create(name: 'Fred') }
228
- .to change { book.read_attribute(:author) }
229
- .from(nil).to('name' => 'Fred')
230
- end
231
-
232
- specify do
233
- expect { muffle(Granite::Form::ValidationError) { existing_association.create! } }
234
- .not_to change { existing_book.read_attribute(:author) }
235
- end
236
- specify do
237
- expect { muffle(Granite::Form::ValidationError) { existing_association.create! } }
238
- .to change { existing_association.reader.try(:attributes) }
239
- .from('name' => 'Johny').to('name' => nil)
240
- end
241
- specify do
242
- expect { existing_association.create!(name: 'Fred') }
243
- .to change { existing_book.read_attribute(:author) }
244
- .from('name' => 'Johny').to('name' => 'Fred')
245
- end
246
- end
247
-
248
- describe '#apply_changes' do
249
- specify do
250
- association.build
251
- expect { association.apply_changes }
252
- .not_to change { association.target.persisted? }.from(false)
253
- end
254
- specify do
255
- association.build(name: 'Fred')
256
- expect { association.apply_changes }
257
- .to change { association.target.persisted? }.to(true)
258
- end
259
- specify do
260
- existing_association.target.mark_for_destruction
261
- expect { existing_association.apply_changes }
262
- .to change { existing_association.target }.to(nil)
263
- end
264
- specify do
265
- existing_association.target.destroy!
266
- expect { existing_association.apply_changes }
267
- .to change { existing_association.target }.to(nil)
268
- end
269
- specify do
270
- existing_association.target.mark_for_destruction
271
- expect { existing_association.apply_changes }
272
- .to change { existing_association.destroyed.try(:name) }.from(nil).to('Johny')
273
- end
274
- specify do
275
- existing_association.target.destroy!
276
- expect { existing_association.apply_changes }
277
- .to change { existing_association.destroyed.try(:name) }.from(nil).to('Johny')
278
- end
279
- end
280
-
281
- describe '#apply_changes!' do
282
- specify do
283
- association.build
284
- expect { association.apply_changes! }
285
- .to raise_error Granite::Form::AssociationChangesNotApplied
286
- end
287
- specify do
288
- association.build(name: 'Fred')
289
- expect { association.apply_changes! }
290
- .to change { association.target.persisted? }.to(true)
291
- end
292
- specify do
293
- existing_association.target.mark_for_destruction
294
- expect { existing_association.apply_changes! }
295
- .to change { existing_association.target }.to(nil)
296
- end
297
- specify do
298
- existing_association.target.destroy!
299
- expect { existing_association.apply_changes! }
300
- .to change { existing_association.target }.to(nil)
301
- end
302
- end
303
-
304
171
  describe '#target' do
305
172
  specify { expect(association.target).to be_nil }
306
173
  specify { expect(existing_association.target).to eq(existing_book.author) }
@@ -369,6 +236,31 @@ describe Granite::Form::Model::Associations::EmbedsOne do
369
236
  end
370
237
  end
371
238
 
239
+ describe '#sync' do
240
+ let!(:author) { association.build(name: 'Fred') }
241
+
242
+ specify { expect { association.sync }.to change { book.read_attribute(:author) }.from(nil).to('name' => 'Fred') }
243
+
244
+ context 'when embedding is nested' do
245
+ before do
246
+ Author.class_eval do
247
+ include Granite::Form::Model::Associations
248
+
249
+ embeds_many :reviews do
250
+ attribute :rating, Integer
251
+ end
252
+ end
253
+
254
+ author.reviews.build(rating: 7)
255
+ end
256
+
257
+ specify do
258
+ expect { association.sync }.to change { book.read_attribute(:author) }
259
+ .from(nil).to('name' => 'Fred', 'reviews' => [{'rating' => 7}])
260
+ end
261
+ end
262
+ end
263
+
372
264
  describe '#clear' do
373
265
  specify { expect(association.clear).to eq(true) }
374
266
  specify { expect { association.clear }.not_to change { association.reader } }
@@ -378,28 +270,6 @@ describe Granite::Form::Model::Associations::EmbedsOne do
378
270
  expect { existing_association.clear }
379
271
  .to change { existing_association.reader.try(:attributes) }.from('name' => 'Johny').to(nil)
380
272
  end
381
- specify do
382
- expect { existing_association.clear }
383
- .to change { existing_book.read_attribute(:author) }.from('name' => 'Johny').to(nil)
384
- end
385
-
386
- context do
387
- before { Author.send(:include, Granite::Form::Model::Callbacks) }
388
- if ActiveModel.version >= Gem::Version.new('5.0.0')
389
- before { Author.before_destroy { throw :abort } }
390
- else
391
- before { Author.before_destroy { false } }
392
- end
393
- specify { expect(existing_association.clear).to eq(false) }
394
- specify do
395
- expect { existing_association.clear }
396
- .not_to change { existing_association.reader }
397
- end
398
- specify do
399
- expect { existing_association.clear }
400
- .not_to change { existing_book.read_attribute(:author).symbolize_keys }
401
- end
402
- end
403
273
  end
404
274
 
405
275
  describe '#reader' do
@@ -441,23 +311,6 @@ describe Granite::Form::Model::Associations::EmbedsOne do
441
311
  expect { association.writer(new_author) }
442
312
  .to change { association.reader.try(:attributes) }.from(nil).to('name' => 'Morty')
443
313
  end
444
- specify do
445
- expect { association.writer(new_author) }
446
- .to change { book.read_attribute(:author) }.from(nil).to('name' => 'Morty')
447
- end
448
-
449
- specify do
450
- expect { association.writer(invalid_author) }
451
- .to raise_error Granite::Form::AssociationChangesNotApplied
452
- end
453
- specify do
454
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { association.writer(invalid_author) } }
455
- .not_to change { association.reader }
456
- end
457
- specify do
458
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { association.writer(invalid_author) } }
459
- .not_to change { book.read_attribute(:author) }
460
- end
461
314
  end
462
315
 
463
316
  context 'persisted owner' do
@@ -468,32 +321,16 @@ describe Granite::Form::Model::Associations::EmbedsOne do
468
321
 
469
322
  specify { expect(association.writer(nil)).to be_nil }
470
323
  specify { expect(association.writer(new_author)).to eq(new_author) }
471
- specify do
472
- expect { association.writer(nil) }
473
- .not_to change { book.read_attribute(:author) }
474
- end
475
324
  specify do
476
325
  expect { association.writer(new_author) }
477
326
  .to change { association.reader.try(:attributes) }.from(nil).to('name' => 'Morty')
478
327
  end
479
- specify do
480
- expect { association.writer(new_author) }
481
- .not_to change { book.read_attribute(:author) }
482
- end
483
328
 
484
329
  specify do
485
330
  expect { association.writer(invalid_author) }
486
331
  .to change { association.reader.try(:attributes) }.from(nil).to('name' => nil)
487
332
  end
488
- specify do
489
- expect { association.writer(invalid_author) }
490
- .not_to change { book.read_attribute(:author) }
491
- end
492
333
 
493
- specify do
494
- expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer(stub_model(:dummy).new) } }
495
- .not_to change { existing_book.read_attribute(:author) }
496
- end
497
334
  specify do
498
335
  expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer(stub_model(:dummy).new) } }
499
336
  .not_to change { existing_association.reader }
@@ -501,33 +338,11 @@ describe Granite::Form::Model::Associations::EmbedsOne do
501
338
 
502
339
  specify { expect(existing_association.writer(nil)).to be_nil }
503
340
  specify { expect(existing_association.writer(new_author)).to eq(new_author) }
504
- specify do
505
- expect { existing_association.writer(nil) }
506
- .to change { existing_book.read_attribute(:author) }.from('name' => 'Johny').to(nil)
507
- end
508
341
  specify do
509
342
  expect { existing_association.writer(new_author) }
510
343
  .to change { existing_association.reader.try(:attributes) }
511
344
  .from('name' => 'Johny').to('name' => 'Morty')
512
345
  end
513
- specify do
514
- expect { existing_association.writer(new_author) }
515
- .to change { existing_book.read_attribute(:author) }
516
- .from('name' => 'Johny').to('name' => 'Morty')
517
- end
518
-
519
- specify do
520
- expect { existing_association.writer(invalid_author) }
521
- .to raise_error Granite::Form::AssociationChangesNotApplied
522
- end
523
- specify do
524
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { existing_association.writer(invalid_author) } }
525
- .not_to change { existing_association.reader }
526
- end
527
- specify do
528
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { existing_association.writer(invalid_author) } }
529
- .not_to change { existing_book.read_attribute(:author) }
530
- end
531
346
  end
532
347
  end
533
348
  end
@@ -11,107 +11,12 @@ describe Granite::Form::Model::Associations::NestedAttributes do
11
11
  embeds_many :projects
12
12
 
13
13
  accepts_nested_attributes_for :profile, :projects
14
-
15
- def save
16
- apply_association_changes!
17
- end
18
14
  end
19
15
  end
20
16
 
21
17
  include_examples 'nested attributes'
22
18
  end
23
19
 
24
- xcontext 'references_one' do
25
- before do
26
- stub_class(:author, ActiveRecord::Base)
27
- stub_class(:user, ActiveRecord::Base)
28
-
29
- stub_model :book do
30
- include Granite::Form::Model::Associations
31
-
32
- references_one :author
33
- references_many :users
34
-
35
- accepts_nested_attributes_for :author, :users
36
- end
37
- end
38
-
39
- context 'references_one' do
40
- let(:book) { Book.new }
41
-
42
- specify { expect { book.author_attributes = {} }.to change { book.author }.to(an_instance_of(Author)) }
43
- specify { expect { book.author_attributes = {name: 'Author'} }.to change { book.author.try(:name) }.to('Author') }
44
- specify { expect { book.author_attributes = {id: 42, name: 'Author'} }.to raise_error Granite::Form::ObjectNotFound }
45
-
46
- context ':reject_if' do
47
- context do
48
- before { Book.accepts_nested_attributes_for :author, reject_if: :all_blank }
49
- specify { expect { book.author_attributes = {name: ''} }.not_to change { book.author } }
50
- end
51
-
52
- context do
53
- before { Book.accepts_nested_attributes_for :author, reject_if: ->(attributes) { attributes['name'].blank? } }
54
- specify { expect { book.author_attributes = {name: ''} }.not_to change { book.author } }
55
- end
56
- end
57
-
58
- context 'existing' do
59
- let(:author) { Author.new(name: 'Author') }
60
- let(:book) { Book.new author: author }
61
-
62
- specify { expect { book.author_attributes = {id: 42, name: 'Author'} }.to raise_error Granite::Form::ObjectNotFound }
63
- specify { expect { book.author_attributes = {id: author.id.to_s, name: 'Author 1'} }.to change { book.author.name }.to('Author 1') }
64
- specify { expect { book.author_attributes = {name: 'Author 1'} }.to change { book.author.name }.to('Author 1') }
65
- specify { expect { book.author_attributes = {name: 'Author 1', _destroy: '1'} }.not_to change { book.author.name } }
66
- specify do
67
- expect do
68
- book.author_attributes = {name: 'Author 1', _destroy: '1'}
69
- book.save { true }
70
- end.not_to change { book.author.name }
71
- end
72
- specify { expect { book.author_attributes = {id: author.id.to_s, name: 'Author 1', _destroy: '1'} }.to change { book.author.name }.to('Author 1') }
73
- specify do
74
- expect do
75
- book.author_attributes = {id: author.id.to_s, name: 'Author 1', _destroy: '1'}
76
- book.save { true }
77
- end.to change { book.author.name }.to('Author 1')
78
- end
79
-
80
- context ':allow_destroy' do
81
- before { Book.accepts_nested_attributes_for :author, allow_destroy: true }
82
-
83
- specify { expect { book.author_attributes = {name: 'Author 1', _destroy: '1'} }.not_to change { book.author.name } }
84
- specify do
85
- expect do
86
- book.author_attributes = {name: 'Author 1', _destroy: '1'}
87
- book.save { true }
88
- end.not_to change { book.author.name }
89
- end
90
- specify { expect { book.author_attributes = {id: author.id.to_s, name: 'Author 1', _destroy: '1'} }.to change { book.author.name }.to('Author 1') }
91
- specify do
92
- expect do
93
- book.author_attributes = {id: author.id.to_s, name: 'Author 1', _destroy: '1'}
94
- book.save { true }
95
- end.to change { book.author }.to(nil)
96
- end
97
- end
98
-
99
- context ':update_only' do
100
- before { Book.accepts_nested_attributes_for :author, update_only: true }
101
-
102
- specify do
103
- expect { book.author_attributes = {id: 42, name: 'Author 1'} }
104
- .to change { book.author.name }.to('Author 1')
105
- end
106
- end
107
- end
108
- end
109
-
110
- context 'references_many' do
111
- let(:book) { Book.new }
112
- end
113
- end
114
-
115
20
  describe '#assign_attributes' do
116
21
  specify 'invent a good example'
117
22
  end