granite-form 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) 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 +15 -0
  8. data/README.md +6 -15
  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 +7 -7
  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/embeds_many.rb +1 -1
  30. data/lib/granite/form/model/associations/reflections/embeds_one.rb +11 -1
  31. data/lib/granite/form/model/associations/reflections/references_any.rb +0 -4
  32. data/lib/granite/form/model/associations/reflections/singular.rb +0 -22
  33. data/lib/granite/form/model/associations.rb +0 -6
  34. data/lib/granite/form/model/attributes/attribute.rb +3 -21
  35. data/lib/granite/form/model/attributes/base.rb +5 -23
  36. data/lib/granite/form/model/attributes/reference_many.rb +1 -1
  37. data/lib/granite/form/model/attributes/reference_one.rb +1 -1
  38. data/lib/granite/form/model/attributes/reflections/attribute.rb +2 -8
  39. data/lib/granite/form/model/attributes/reflections/base/build_type_definition.rb +38 -0
  40. data/lib/granite/form/model/attributes/reflections/base.rb +20 -17
  41. data/lib/granite/form/model/attributes/reflections/collection/build_type_definition.rb +19 -0
  42. data/lib/granite/form/model/attributes/reflections/dictionary/build_type_definition.rb +19 -0
  43. data/lib/granite/form/model/attributes/reflections/dictionary.rb +0 -3
  44. data/lib/granite/form/model/attributes/reflections/reference_one.rb +0 -6
  45. data/lib/granite/form/model/attributes/reflections/represents/build_type_definition.rb +73 -0
  46. data/lib/granite/form/model/attributes/reflections/represents.rb +10 -2
  47. data/lib/granite/form/model/attributes/represents.rb +22 -37
  48. data/lib/granite/form/model/attributes.rb +10 -2
  49. data/lib/granite/form/model/persistence.rb +1 -19
  50. data/lib/granite/form/model/representation.rb +1 -0
  51. data/lib/granite/form/model/validations.rb +6 -0
  52. data/lib/granite/form/model.rb +1 -3
  53. data/lib/granite/form/types/active_support/time_zone.rb +2 -0
  54. data/lib/granite/form/types/array.rb +2 -0
  55. data/lib/granite/form/types/big_decimal.rb +2 -0
  56. data/lib/granite/form/types/boolean.rb +2 -0
  57. data/lib/granite/form/types/collection.rb +11 -0
  58. data/lib/granite/form/types/date.rb +2 -0
  59. data/lib/granite/form/types/date_time.rb +2 -0
  60. data/lib/granite/form/types/dictionary.rb +23 -0
  61. data/lib/granite/form/types/float.rb +2 -0
  62. data/lib/granite/form/types/has_subtype.rb +18 -0
  63. data/lib/granite/form/types/hash_with_action_controller_parameters.rb +2 -0
  64. data/lib/granite/form/types/integer.rb +2 -0
  65. data/lib/granite/form/types/object.rb +28 -0
  66. data/lib/granite/form/types/string.rb +2 -0
  67. data/lib/granite/form/types/time.rb +2 -0
  68. data/lib/granite/form/types/uuid.rb +2 -0
  69. data/lib/granite/form/types.rb +3 -0
  70. data/lib/granite/form/util.rb +55 -0
  71. data/lib/granite/form/version.rb +1 -1
  72. data/lib/granite/form.rb +1 -0
  73. data/spec/granite/form/active_record/associations_spec.rb +16 -18
  74. data/spec/granite/form/model/associations/embeds_many_spec.rb +29 -305
  75. data/spec/granite/form/model/associations/embeds_one_spec.rb +27 -212
  76. data/spec/granite/form/model/associations/nested_attributes_spec.rb +0 -95
  77. data/spec/granite/form/model/associations/references_many_spec.rb +5 -326
  78. data/spec/granite/form/model/associations/references_one_spec.rb +7 -279
  79. data/spec/granite/form/model/associations/reflections/embeds_any_spec.rb +1 -2
  80. data/spec/granite/form/model/associations/reflections/embeds_many_spec.rb +18 -26
  81. data/spec/granite/form/model/associations/reflections/embeds_one_spec.rb +16 -23
  82. data/spec/granite/form/model/associations/reflections/references_many_spec.rb +1 -1
  83. data/spec/granite/form/model/associations/reflections/references_one_spec.rb +1 -22
  84. data/spec/granite/form/model/associations/validations_spec.rb +0 -3
  85. data/spec/granite/form/model/associations_spec.rb +3 -24
  86. data/spec/granite/form/model/attributes/attribute_spec.rb +0 -29
  87. data/spec/granite/form/model/attributes/reflections/attribute_spec.rb +0 -9
  88. data/spec/granite/form/model/attributes/reflections/base/build_type_definition_spec.rb +27 -0
  89. data/spec/granite/form/model/attributes/reflections/base_spec.rb +16 -10
  90. data/spec/granite/form/model/attributes/reflections/collection/build_type_definition_spec.rb +24 -0
  91. data/spec/granite/form/model/attributes/reflections/dictionary/build_type_definition_spec.rb +24 -0
  92. data/spec/granite/form/model/attributes/reflections/dictionary_spec.rb +0 -6
  93. data/spec/granite/form/model/attributes/reflections/represents/build_type_definition_spec.rb +129 -0
  94. data/spec/granite/form/model/attributes/reflections/represents_spec.rb +43 -20
  95. data/spec/granite/form/model/attributes/represents_spec.rb +78 -55
  96. data/spec/granite/form/model/attributes_spec.rb +84 -23
  97. data/spec/granite/form/model/dirty_spec.rb +1 -7
  98. data/spec/granite/form/model/persistence_spec.rb +0 -2
  99. data/spec/granite/form/model/representation_spec.rb +4 -7
  100. data/spec/granite/form/model/validations/associated_spec.rb +2 -4
  101. data/spec/granite/form/model/validations/nested_spec.rb +2 -4
  102. data/spec/granite/form/model/validations_spec.rb +28 -1
  103. data/spec/granite/form/types/collection_spec.rb +22 -0
  104. data/spec/granite/form/types/dictionary_spec.rb +32 -0
  105. data/spec/granite/form/types/has_subtype_spec.rb +20 -0
  106. data/spec/granite/form/types/object_spec.rb +50 -4
  107. data/spec/granite/form/util_spec.rb +108 -0
  108. data/spec/spec_helper.rb +0 -15
  109. data/spec/support/active_record.rb +23 -0
  110. data/spec/support/shared/nested_attribute_examples.rb +3 -21
  111. metadata +56 -51
  112. data/.github/workflows/main.yml +0 -29
  113. data/gemfiles/rails.4.2.gemfile +0 -15
  114. data/lib/granite/form/model/attributes/collection.rb +0 -19
  115. data/lib/granite/form/model/attributes/dictionary.rb +0 -28
  116. data/lib/granite/form/model/attributes/localized.rb +0 -44
  117. data/lib/granite/form/model/attributes/reflections/localized.rb +0 -45
  118. data/lib/granite/form/model/callbacks.rb +0 -72
  119. data/lib/granite/form/model/lifecycle.rb +0 -309
  120. data/lib/granite/form/model/localization.rb +0 -26
  121. data/spec/granite/form/model/attributes/collection_spec.rb +0 -72
  122. data/spec/granite/form/model/attributes/dictionary_spec.rb +0 -100
  123. data/spec/granite/form/model/attributes/localized_spec.rb +0 -103
  124. data/spec/granite/form/model/attributes/reflections/localized_spec.rb +0 -37
  125. data/spec/granite/form/model/callbacks_spec.rb +0 -337
  126. data/spec/granite/form/model/lifecycle_spec.rb +0 -356
@@ -4,7 +4,7 @@ describe Granite::Form::Model::Associations::ReferencesMany do
4
4
  before do
5
5
  stub_model(:dummy)
6
6
  stub_class(:author, ActiveRecord::Base) do
7
- scope :name_starts_with_a, -> { where('name LIKE "a%"') }
7
+ scope :name_starts_with_a, -> { where('name ILIKE "a%"') }
8
8
 
9
9
  validates :name, presence: true
10
10
  end
@@ -33,330 +33,9 @@ describe Granite::Form::Model::Associations::ReferencesMany do
33
33
  end
34
34
 
35
35
  describe 'book#inspect' do
36
- specify { expect(existing_book.inspect).to eq('#<Book authors: #<ReferencesMany [#<Author id: 1, name: "Rick">]>, title: "Genesis", author_ids: [1]>') }
37
- end
38
-
39
- describe '#build' do
40
- specify { expect(association.build).to be_a Author }
41
- specify { expect(association.build).not_to be_persisted }
42
-
43
- specify do
44
- expect { association.build(name: 'Morty') }
45
- .to change { book.author_ids }
46
- .from([]).to([nil])
47
- end
48
- specify do
49
- expect { association.build(name: 'Morty') }
50
- .to change { association.reader }.from([])
51
- .to([an_instance_of(Author).and(have_attributes(name: 'Morty'))])
52
- end
53
-
54
- specify do
55
- expect { existing_association.build(name: 'Morty') }
56
- .to change { existing_book.author_ids }
57
- .from([author.id]).to([author.id, nil])
58
- end
59
- specify do
60
- expect { existing_association.build(name: 'Morty') }
61
- .to change { existing_association.reader }.from([author])
62
- .to([author, an_instance_of(Author).and(have_attributes(name: 'Morty'))])
63
- end
64
-
65
- context 'dirty' do
66
- before do
67
- Book.include Granite::Form::Model::Dirty
68
- end
69
-
70
- specify do
71
- expect { existing_association.build(name: 'Morty') }
72
- .to change { existing_book.changes }
73
- .from({}).to('author_ids' => [[author.id], [author.id, nil]])
74
- end
75
- end
76
- end
77
-
78
- describe '#create' do
79
- specify { expect(association.create).to be_a Author }
80
- specify { expect(association.create).not_to be_persisted }
81
-
82
- specify { expect(association.create(name: 'Morty')).to be_a Author }
83
- specify { expect(association.create(name: 'Morty')).to be_persisted }
84
-
85
- specify do
86
- expect { association.create }
87
- .to change { book.author_ids }
88
- .from([]).to([nil])
89
- end
90
- specify do
91
- expect { association.create }
92
- .to change { association.target }
93
- .from([]).to([an_instance_of(Author).and(be_new_record)])
94
- end
95
-
96
- specify do
97
- expect { association.create(name: 'Morty') }
98
- .to change { book.author_ids }
99
- .from([]).to([be_a(Integer)])
100
- end
101
- specify do
102
- expect { association.create(name: 'Morty') }
103
- .to change { association.target }.from([])
104
- .to([an_instance_of(Author)
105
- .and(have_attributes(name: 'Morty'))
106
- .and(be_persisted)])
107
- end
108
-
109
- specify do
110
- expect { existing_association.create }
111
- .to change { existing_book.author_ids }
112
- .from([author.id]).to([author.id, nil])
113
- end
114
- specify do
115
- expect { existing_association.create }
116
- .to change { existing_association.reader }.from([author])
117
- .to([author, an_instance_of(Author).and(be_new_record)])
118
- end
119
-
120
- specify do
121
- expect { existing_association.create(name: 'Morty') }
122
- .to change { existing_book.author_ids }
123
- .from([author.id]).to([author.id, be_a(Integer)])
124
- end
125
- specify do
126
- expect { existing_association.create(name: 'Morty') }
127
- .to change { existing_association.reader }.from([author])
128
- .to([author, an_instance_of(Author)
129
- .and(have_attributes(name: 'Morty'))
130
- .and(be_persisted)])
131
- end
132
-
133
- context 'dirty' do
134
- before do
135
- Book.include Granite::Form::Model::Dirty
136
- end
137
-
138
- specify do
139
- expect { existing_association.create(name: 'Morty') }
140
- .to change { existing_book.changes }
141
- .from({}).to('author_ids' => [[author.id], [author.id, be_a(Integer)]])
142
- end
143
- end
144
- end
145
-
146
- describe '#create!' do
147
- specify { expect { association.create! }.to raise_error ActiveRecord::RecordInvalid }
148
-
149
- specify { expect(association.create!(name: 'Morty')).to be_a Author }
150
- specify { expect(association.create!(name: 'Morty')).to be_persisted }
151
-
152
- specify do
153
- expect { muffle(ActiveRecord::RecordInvalid) { association.create! } }
154
- .to change { book.author_ids }
155
- .from([]).to([nil])
156
- end
157
- specify do
158
- expect { muffle(ActiveRecord::RecordInvalid) { association.create! } }
159
- .to change { association.target }
160
- .from([]).to([an_instance_of(Author).and(be_new_record)])
161
- end
162
-
163
- specify do
164
- expect { association.create!(name: 'Morty') }
165
- .to change { book.author_ids }
166
- .from([]).to([be_a(Integer)])
167
- end
168
- specify do
169
- expect { association.create!(name: 'Morty') }
170
- .to change { association.target }.from([])
171
- .to([an_instance_of(Author)
172
- .and(have_attributes(name: 'Morty'))
173
- .and(be_persisted)])
174
- end
175
-
176
- specify do
177
- expect { muffle(ActiveRecord::RecordInvalid) { existing_association.create! } }
178
- .to change { existing_book.author_ids }
179
- .from([author.id]).to([author.id, nil])
180
- end
181
- specify do
182
- expect { muffle(ActiveRecord::RecordInvalid) { existing_association.create! } }
183
- .to change { existing_association.reader }.from([author])
184
- .to([author, an_instance_of(Author).and(be_new_record)])
185
- end
186
-
187
- specify do
188
- expect { existing_association.create!(name: 'Morty') }
189
- .to change { existing_book.author_ids }
190
- .from([author.id]).to([author.id, be_a(Integer)])
191
- end
192
- specify do
193
- expect { existing_association.create!(name: 'Morty') }
194
- .to change { existing_association.reader }.from([author])
195
- .to([author, an_instance_of(Author)
196
- .and(have_attributes(name: 'Morty'))
197
- .and(be_persisted)])
198
- end
199
- end
200
-
201
- describe '#apply_changes' do
202
- specify do
203
- association.build
204
- expect(association.apply_changes).to eq(false)
205
- end
206
- specify do
207
- association.build
208
- expect { association.apply_changes }
209
- .not_to change { association.target.map(&:persisted?) }
210
- .from([false])
211
- end
212
- specify do
213
- association.build(name: 'Rick')
214
- expect(association.apply_changes).to eq(true)
215
- end
216
- specify do
217
- association.build(name: 'Rick')
218
- expect { association.apply_changes }
219
- .to change { association.target.map(&:persisted?) }
220
- .from([false]).to([true])
221
- end
222
- specify do
223
- association.build(name: 'Rick')
224
- expect { association.apply_changes }
225
- .to change { book.author_ids }
226
- .from([nil]).to([be_a(Integer)])
227
- end
228
- specify do
229
- existing_association.target.first.name = 'Morty'
230
- expect { existing_association.apply_changes }
231
- .not_to change { author.reload.name }
232
- end
233
- specify do
234
- existing_association.target.first.mark_for_destruction
235
- existing_association.build(name: 'Morty')
236
- expect { existing_association.apply_changes }
237
- .to change { existing_book.author_ids }
238
- .from([author.id, nil]).to([author.id, be_a(Integer)])
239
- end
240
- specify do
241
- existing_association.target.first.mark_for_destruction
242
- existing_association.build(name: 'Morty')
243
- expect { existing_association.apply_changes }
244
- .to change { existing_association.target.map(&:persisted?) }
245
- .from([true, false]).to([true, true])
246
- end
247
- specify do
248
- existing_association.target.first.destroy!
249
- existing_association.build(name: 'Morty')
250
- expect { existing_association.apply_changes }
251
- .to change { existing_book.author_ids }
252
- .from([author.id, nil]).to([author.id, be_a(Integer)])
253
- end
254
- specify do
255
- existing_association.target.first.destroy!
256
- existing_association.build(name: 'Morty')
257
- expect { existing_association.apply_changes }
258
- .to change { existing_association.target.map(&:persisted?) }
259
- .from([false, false]).to([false, true])
260
- end
261
-
262
- context ':autosave' do
263
- before do
264
- Book.references_many :authors, autosave: true
265
- end
266
-
267
- specify do
268
- association.build
269
- expect(association.apply_changes).to eq(false)
270
- end
271
- specify do
272
- association.build
273
- expect { association.apply_changes }
274
- .not_to change { association.target.map(&:persisted?) }
275
- .from([false])
276
- end
277
- specify do
278
- association.build(name: 'Rick')
279
- expect(association.apply_changes).to eq(true)
280
- end
281
- specify do
282
- association.build(name: 'Rick')
283
- expect { association.apply_changes }
284
- .to change { association.target.map(&:persisted?) }
285
- .from([false]).to([true])
286
- end
287
- specify do
288
- association.build(name: 'Rick')
289
- expect { association.apply_changes }
290
- .to change { book.author_ids }
291
- .from([nil]).to([be_a(Integer)])
292
- end
293
- specify do
294
- existing_association.target.first.name = 'Morty'
295
- expect { existing_association.apply_changes }
296
- .to change { author.reload.name }
297
- .from('Rick').to('Morty')
298
- end
299
- specify do
300
- existing_association.target.first.mark_for_destruction
301
- existing_association.build(name: 'Morty')
302
- expect { existing_association.apply_changes }
303
- .to change { existing_book.author_ids }
304
- .from([author.id, nil]).to([author.id, be_a(Integer)])
305
- end
306
- specify do
307
- existing_association.target.first.mark_for_destruction
308
- existing_association.build(name: 'Morty')
309
- expect { existing_association.apply_changes }
310
- .to change { existing_association.target.map(&:persisted?) }
311
- .from([true, false]).to([false, true])
312
- end
313
- specify do
314
- existing_association.target.first.destroy!
315
- existing_association.build(name: 'Morty')
316
- expect { existing_association.apply_changes }
317
- .to change { existing_book.author_ids }
318
- .from([author.id, nil]).to([author.id, be_a(Integer)])
319
- end
320
- specify do
321
- existing_association.target.first.destroy!
322
- existing_association.build(name: 'Morty')
323
- expect { existing_association.apply_changes }
324
- .to change { existing_association.target.map(&:persisted?) }
325
- .from([false, false]).to([false, true])
326
- end
327
- end
328
- end
329
-
330
- describe '#apply_changes!' do
331
- specify do
332
- association.build
333
- expect { association.apply_changes! }
334
- .to raise_error(Granite::Form::AssociationChangesNotApplied)
335
- end
336
- specify do
337
- association.build
338
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { association.apply_changes! } }
339
- .not_to change { association.target.map(&:persisted?) }
340
- .from([false])
341
- end
342
-
343
- context ':autosave' do
344
- before do
345
- Book.references_many :authors, autosave: true
346
- end
347
-
348
- specify do
349
- association.build
350
- expect { association.apply_changes! }
351
- .to raise_error(Granite::Form::AssociationChangesNotApplied)
352
- end
353
- specify do
354
- association.build
355
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { association.apply_changes! } }
356
- .not_to change { association.target.map(&:persisted?) }
357
- .from([false])
358
- end
359
- end
36
+ specify { expect(existing_book.inspect).to eq(<<~STR.chomp) }
37
+ #<Book authors: #<ReferencesMany #{[author].inspect.truncate(50, omission: '...]')}>, title: "Genesis", author_ids: [#{author.id}]>
38
+ STR
360
39
  end
361
40
 
362
41
  describe '#scope' do
@@ -536,7 +215,7 @@ describe Granite::Form::Model::Associations::ReferencesMany do
536
215
  end
537
216
  specify do
538
217
  expect { association.concat(new_author1) }
539
- .to change { book.read_attribute(:author_ids) }.from([]).to([1])
218
+ .to change { book.read_attribute(:author_ids) }.from([]).to([new_author1.id])
540
219
  end
541
220
 
542
221
  specify do
@@ -29,281 +29,9 @@ describe Granite::Form::Model::Associations::ReferencesOne do
29
29
  end
30
30
 
31
31
  describe 'book#inspect' do
32
- specify { expect(existing_book.inspect).to eq('#<Book author: #<ReferencesOne #<Author id: 1, name: "Johny">>, title: "My Life", author_id: 1>') }
33
- end
34
-
35
- describe '#build' do
36
- specify { expect(association.build).to be_a Author }
37
- specify { expect(association.build).not_to be_persisted }
38
-
39
- specify do
40
- expect { association.build(name: 'Morty') }
41
- .not_to change { book.author_id }
42
- end
43
- specify do
44
- expect { association.build(name: 'Morty') }
45
- .to change { book.author }.from(nil)
46
- .to(an_instance_of(Author).and(have_attributes(name: 'Morty')))
47
- end
48
-
49
- specify do
50
- expect { existing_association.build(name: 'Morty') }
51
- .to change { existing_book.author_id }
52
- .from(author.id).to(nil)
53
- end
54
- specify do
55
- expect { existing_association.build(name: 'Morty') }
56
- .to change { existing_book.author }.from(author)
57
- .to(an_instance_of(Author).and(have_attributes(name: 'Morty')))
58
- end
59
-
60
- context 'dirty' do
61
- before do
62
- Book.include Granite::Form::Model::Dirty
63
- end
64
-
65
- specify do
66
- expect { existing_association.build(name: 'Morty') }
67
- .to change { existing_book.changes }
68
- .from({}).to('author_id' => [author.id, nil])
69
- end
70
- end
71
- end
72
-
73
- describe '#create' do
74
- specify { expect(association.create).to be_a Author }
75
- specify { expect(association.create).not_to be_persisted }
76
-
77
- specify { expect(association.create(name: 'Fred')).to be_a Author }
78
- specify { expect(association.create(name: 'Fred')).to be_persisted }
79
-
80
- specify do
81
- expect { association.create }
82
- .not_to change { book.author_id }
83
- end
84
- specify do
85
- expect { association.create(name: 'Fred') }
86
- .to change { book.author_id }
87
- .from(nil).to(be_a(Integer))
88
- end
89
-
90
- specify do
91
- expect { existing_association.create }
92
- .to change { existing_book.author_id }
93
- .from(author.id).to(nil)
94
- end
95
- specify do
96
- expect { existing_association.create(name: 'Fred') }
97
- .to change { existing_book.author_id }
98
- .from(author.id).to(be_a(Integer))
99
- end
100
-
101
- context 'dirty' do
102
- before do
103
- Book.include Granite::Form::Model::Dirty
104
- end
105
-
106
- specify do
107
- expect { existing_association.create(name: 'Fred') }
108
- .to change { existing_book.changes }
109
- .from({}).to('author_id' => [author.id, be_a(Integer)])
110
- end
111
- end
112
- end
113
-
114
- describe '#create!' do
115
- specify { expect { association.create! }.to raise_error ActiveRecord::RecordInvalid }
116
- specify do
117
- expect { muffle(ActiveRecord::RecordInvalid) { association.create! } }
118
- .to change { association.target }
119
- .from(nil).to(an_instance_of(Author))
120
- end
121
-
122
- specify { expect(association.create!(name: 'Fred')).to be_a Author }
123
- specify { expect(association.create!(name: 'Fred')).to be_persisted }
124
-
125
- specify do
126
- expect { muffle(ActiveRecord::RecordInvalid) { association.create! } }
127
- .not_to change { book.author_id }
128
- end
129
- specify do
130
- expect { muffle(ActiveRecord::RecordInvalid) { association.create! } }
131
- .to change { association.reader.try(:attributes).try(:slice, 'name') }
132
- .from(nil).to('name' => nil)
133
- end
134
- specify do
135
- expect { association.create(name: 'Fred') }
136
- .to change { book.author_id }
137
- .from(nil).to(be_a(Integer))
138
- end
139
-
140
- specify do
141
- expect { muffle(ActiveRecord::RecordInvalid) { existing_association.create! } }
142
- .to change { existing_book.author_id }
143
- .from(author.id).to(nil)
144
- end
145
- specify do
146
- expect { muffle(ActiveRecord::RecordInvalid) { existing_association.create! } }
147
- .to change { existing_association.reader.try(:attributes).try(:slice, 'name') }
148
- .from('name' => 'Johny').to('name' => nil)
149
- end
150
- specify do
151
- expect { existing_association.create!(name: 'Fred') }
152
- .to change { existing_book.author_id }
153
- .from(author.id).to(be_a(Integer))
154
- end
155
- end
156
-
157
- context do
158
- shared_examples 'apply_changes' do |method|
159
- specify do
160
- association.build(name: 'Fred')
161
- expect(association.send(method)).to eq(true)
162
- end
163
- specify do
164
- association.build(name: 'Fred')
165
- expect { association.send(method) }
166
- .to change { association.target.persisted? }.to(true)
167
- end
168
- specify do
169
- association.build(name: 'Fred')
170
- expect { association.send(method) }
171
- .to change { book.author_id }
172
- .from(nil).to(be_a(Integer))
173
- end
174
- specify do
175
- existing_association.target.name = 'Fred'
176
- expect { existing_association.send(method) }
177
- .not_to change { author.reload.name }
178
- end
179
- specify do
180
- existing_association.target.mark_for_destruction
181
- expect { existing_association.send(method) }
182
- .not_to change { existing_association.target.destroyed? }
183
- end
184
- specify do
185
- existing_association.target.mark_for_destruction
186
- expect { existing_association.send(method) }
187
- .not_to change { existing_book.author_id }
188
- end
189
- specify do
190
- existing_association.target.destroy!
191
- expect { existing_association.send(method) }
192
- .not_to change { existing_association.target.destroyed? }
193
- end
194
- specify do
195
- existing_association.target.destroy!
196
- expect { existing_association.send(method) }
197
- .not_to change { existing_book.author_id }
198
- end
199
-
200
- context ':autosave' do
201
- before do
202
- Book.references_one :author, autosave: true
203
- end
204
-
205
- specify do
206
- association.build(name: 'Fred')
207
- expect(association.send(method)).to eq(true)
208
- end
209
- specify do
210
- association.build(name: 'Fred')
211
- expect { association.send(method) }
212
- .to change { association.target.persisted? }.to(true)
213
- end
214
- specify do
215
- existing_association.target.name = 'Fred'
216
- expect { existing_association.send(method) }
217
- .to change { author.reload.name }.from('Johny').to('Fred')
218
- end
219
- specify do
220
- existing_association.target.mark_for_destruction
221
- expect { existing_association.send(method) }
222
- .to change { existing_association.target.destroyed? }
223
- .from(false).to(true)
224
- end
225
- specify do
226
- existing_association.target.mark_for_destruction
227
- expect { existing_association.send(method) }
228
- .not_to change { existing_book.author_id }
229
- .from(author.id)
230
- end
231
- specify do
232
- existing_association.target.destroy!
233
- expect { existing_association.send(method) }
234
- .not_to change { existing_association.target.destroyed? }
235
- .from(true)
236
- end
237
- specify do
238
- existing_association.target.destroy!
239
- expect { existing_association.send(method) }
240
- .not_to change { existing_book.author_id }
241
- .from(author.id)
242
- end
243
- end
244
- end
245
-
246
- describe '#apply_changes' do
247
- include_examples 'apply_changes', :apply_changes
248
-
249
- specify do
250
- association.build
251
- expect(association.apply_changes).to eq(false)
252
- end
253
- specify do
254
- association.build
255
- expect { association.apply_changes }
256
- .not_to change { association.target.persisted? }.from(false)
257
- end
258
-
259
- context ':autosave' do
260
- before do
261
- Book.references_one :author, autosave: true
262
- end
263
-
264
- specify do
265
- association.build
266
- expect(association.apply_changes).to eq(false)
267
- end
268
- specify do
269
- association.build
270
- expect { association.apply_changes }
271
- .not_to change { association.target.persisted? }.from(false)
272
- end
273
- end
274
- end
275
-
276
- describe '#apply_changes!' do
277
- include_examples 'apply_changes', :apply_changes!
278
-
279
- specify do
280
- association.build
281
- expect { association.apply_changes! }
282
- .to raise_error(Granite::Form::AssociationChangesNotApplied)
283
- end
284
- specify do
285
- association.build
286
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { association.apply_changes! } }
287
- .not_to change { association.target.persisted? }.from(false)
288
- end
289
-
290
- context ':autosave' do
291
- before do
292
- Book.references_one :author, autosave: true
293
- end
294
-
295
- specify do
296
- association.build
297
- expect { association.apply_changes! }
298
- .to raise_error(Granite::Form::AssociationChangesNotApplied)
299
- end
300
- specify do
301
- association.build
302
- expect { muffle(Granite::Form::AssociationChangesNotApplied) { association.apply_changes! } }
303
- .not_to change { association.target.persisted? }.from(false)
304
- end
305
- end
306
- end
32
+ specify { expect(existing_book.inspect).to eq(<<~STR.chomp) }
33
+ #<Book author: #<ReferencesOne #{author.inspect.truncate(50)}>, title: "My Life", author_id: #{author.id}>
34
+ STR
307
35
  end
308
36
 
309
37
  describe '#target' do
@@ -384,7 +112,7 @@ describe Granite::Form::Model::Associations::ReferencesOne do
384
112
  end
385
113
 
386
114
  context 'persisted owner' do
387
- let(:new_author) { Author.create(name: 'Morty') }
115
+ let(:new_author) { Author.create!(name: 'Morty') }
388
116
 
389
117
  specify do
390
118
  expect { association.writer(stub_model(:dummy).new) }
@@ -399,7 +127,7 @@ describe Granite::Form::Model::Associations::ReferencesOne do
399
127
  end
400
128
  specify do
401
129
  expect { association.writer(new_author) }
402
- .to change { association.reader.try(:attributes) }.from(nil).to('id' => 1, 'name' => 'Morty')
130
+ .to change { association.reader }.from(nil).to(new_author)
403
131
  end
404
132
  specify do
405
133
  expect { association.writer(new_author) }
@@ -432,8 +160,8 @@ describe Granite::Form::Model::Associations::ReferencesOne do
432
160
  end
433
161
  specify do
434
162
  expect { existing_association.writer(new_author) }
435
- .to change { existing_association.reader.try(:attributes) }
436
- .from('id' => 1, 'name' => 'Johny').to('id' => 2, 'name' => 'Morty')
163
+ .to change { existing_association.reader }
164
+ .from(author).to(new_author)
437
165
  end
438
166
  specify do
439
167
  expect { existing_association.writer(new_author) }
@@ -7,7 +7,6 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsAny do
7
7
 
8
8
  before do
9
9
  stub_model(:project) do
10
- include Granite::Form::Model::Lifecycle
11
10
  attribute :title, String
12
11
  end
13
12
  stub_model(:user) do
@@ -20,7 +19,7 @@ describe Granite::Form::Model::Associations::Reflections::EmbedsAny do
20
19
 
21
20
  it { is_expected.to be_a(Granite::Form::Model) }
22
21
  it { is_expected.to be_a(Granite::Form::Model::Primary) }
23
- it { is_expected.to be_a(Granite::Form::Model::Lifecycle) }
22
+ it { is_expected.to be_a(Granite::Form::Model::Persistence) }
24
23
  it { is_expected.to be_a(Granite::Form::Model::Associations) }
25
24
 
26
25
  context 'when Granite::Form.base_concern is defined' do