granite-form 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (133) 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 +14 -0
  8. data/README.md +0 -2
  9. data/Rakefile +4 -0
  10. data/docker-compose.yml +14 -0
  11. data/gemfiles/rails.5.0.gemfile +0 -1
  12. data/gemfiles/rails.5.1.gemfile +0 -1
  13. data/gemfiles/rails.5.2.gemfile +0 -1
  14. data/granite-form.gemspec +16 -15
  15. data/lib/granite/form/active_record/associations.rb +1 -1
  16. data/lib/granite/form/base.rb +1 -2
  17. data/lib/granite/form/config.rb +10 -10
  18. data/lib/granite/form/errors.rb +0 -15
  19. data/lib/granite/form/model/associations/base.rb +0 -4
  20. data/lib/granite/form/model/associations/collection/embedded.rb +2 -1
  21. data/lib/granite/form/model/associations/collection/proxy.rb +1 -1
  22. data/lib/granite/form/model/associations/embeds_any.rb +7 -0
  23. data/lib/granite/form/model/associations/embeds_many.rb +9 -58
  24. data/lib/granite/form/model/associations/embeds_one.rb +7 -36
  25. data/lib/granite/form/model/associations/nested_attributes.rb +8 -8
  26. data/lib/granite/form/model/associations/persistence_adapters/active_record.rb +0 -4
  27. data/lib/granite/form/model/associations/persistence_adapters/base.rb +0 -4
  28. data/lib/granite/form/model/associations/references_many.rb +0 -32
  29. data/lib/granite/form/model/associations/references_one.rb +0 -28
  30. data/lib/granite/form/model/associations/reflections/embeds_any.rb +1 -1
  31. data/lib/granite/form/model/associations/reflections/references_any.rb +0 -4
  32. data/lib/granite/form/model/associations/reflections/references_many.rb +3 -1
  33. data/lib/granite/form/model/associations/reflections/references_one.rb +3 -3
  34. data/lib/granite/form/model/associations/reflections/singular.rb +0 -8
  35. data/lib/granite/form/model/associations.rb +0 -6
  36. data/lib/granite/form/model/attributes/attribute.rb +1 -1
  37. data/lib/granite/form/model/attributes/base.rb +14 -17
  38. data/lib/granite/form/model/attributes/collection.rb +1 -1
  39. data/lib/granite/form/model/attributes/dictionary.rb +1 -1
  40. data/lib/granite/form/model/attributes/localized.rb +1 -1
  41. data/lib/granite/form/model/attributes/reference_many.rb +1 -1
  42. data/lib/granite/form/model/attributes/reference_one.rb +1 -9
  43. data/lib/granite/form/model/attributes/reflections/attribute.rb +0 -6
  44. data/lib/granite/form/model/attributes/reflections/base.rb +9 -12
  45. data/lib/granite/form/model/attributes/reflections/reference_one.rb +0 -10
  46. data/lib/granite/form/model/persistence.rb +1 -19
  47. data/lib/granite/form/model/validations/nested.rb +1 -1
  48. data/lib/granite/form/model.rb +0 -2
  49. data/lib/granite/form/types/active_support/time_zone.rb +22 -0
  50. data/lib/granite/form/types/array.rb +17 -0
  51. data/lib/granite/form/types/big_decimal.rb +15 -0
  52. data/lib/granite/form/types/boolean.rb +38 -0
  53. data/lib/granite/form/types/date.rb +15 -0
  54. data/lib/granite/form/types/date_time.rb +15 -0
  55. data/lib/granite/form/types/float.rb +15 -0
  56. data/lib/granite/form/types/hash_with_action_controller_parameters.rb +18 -0
  57. data/lib/granite/form/types/integer.rb +13 -0
  58. data/lib/granite/form/types/object.rb +30 -0
  59. data/lib/granite/form/types/string.rb +13 -0
  60. data/lib/granite/form/types/time.rb +15 -0
  61. data/lib/granite/form/types/uuid.rb +22 -0
  62. data/lib/granite/form/types.rb +15 -0
  63. data/lib/granite/form/version.rb +1 -1
  64. data/lib/granite/form.rb +19 -118
  65. data/spec/{lib/granite → granite}/form/active_record/associations_spec.rb +16 -18
  66. data/spec/{lib/granite → granite}/form/active_record/nested_attributes_spec.rb +0 -1
  67. data/spec/{lib/granite → granite}/form/config_spec.rb +22 -10
  68. data/spec/granite/form/extensions_spec.rb +12 -0
  69. data/spec/{lib/granite → granite}/form/model/associations/embeds_many_spec.rb +29 -305
  70. data/spec/{lib/granite → granite}/form/model/associations/embeds_one_spec.rb +27 -212
  71. data/spec/granite/form/model/associations/nested_attributes_spec.rb +23 -0
  72. data/spec/{lib/granite → granite}/form/model/associations/persistence_adapters/active_record_spec.rb +0 -0
  73. data/spec/granite/form/model/associations/references_many_spec.rb +251 -0
  74. data/spec/granite/form/model/associations/references_one_spec.rb +173 -0
  75. data/spec/{lib/granite → granite}/form/model/associations/reflections/embeds_any_spec.rb +1 -2
  76. data/spec/{lib/granite → granite}/form/model/associations/reflections/embeds_many_spec.rb +18 -26
  77. data/spec/{lib/granite → granite}/form/model/associations/reflections/embeds_one_spec.rb +16 -23
  78. data/spec/{lib/granite → granite}/form/model/associations/reflections/references_many_spec.rb +1 -1
  79. data/spec/{lib/granite → granite}/form/model/associations/reflections/references_one_spec.rb +1 -22
  80. data/spec/{lib/granite → granite}/form/model/associations/validations_spec.rb +0 -3
  81. data/spec/{lib/granite → granite}/form/model/associations_spec.rb +3 -24
  82. data/spec/{lib/granite → granite}/form/model/attributes/attribute_spec.rb +4 -46
  83. data/spec/{lib/granite → granite}/form/model/attributes/base_spec.rb +11 -2
  84. data/spec/{lib/granite → granite}/form/model/attributes/collection_spec.rb +0 -0
  85. data/spec/{lib/granite → granite}/form/model/attributes/dictionary_spec.rb +0 -0
  86. data/spec/{lib/granite → granite}/form/model/attributes/localized_spec.rb +1 -1
  87. data/spec/{lib/granite → granite}/form/model/attributes/reflections/attribute_spec.rb +0 -12
  88. data/spec/{lib/granite → granite}/form/model/attributes/reflections/base_spec.rb +1 -1
  89. data/spec/{lib/granite → granite}/form/model/attributes/reflections/collection_spec.rb +0 -0
  90. data/spec/{lib/granite → granite}/form/model/attributes/reflections/dictionary_spec.rb +0 -0
  91. data/spec/{lib/granite → granite}/form/model/attributes/reflections/localized_spec.rb +0 -0
  92. data/spec/{lib/granite → granite}/form/model/attributes/reflections/represents_spec.rb +0 -0
  93. data/spec/{lib/granite → granite}/form/model/attributes/represents_spec.rb +0 -0
  94. data/spec/{lib/granite → granite}/form/model/attributes_spec.rb +0 -0
  95. data/spec/{lib/granite → granite}/form/model/conventions_spec.rb +0 -0
  96. data/spec/{lib/granite → granite}/form/model/dirty_spec.rb +1 -1
  97. data/spec/{lib/granite → granite}/form/model/persistence_spec.rb +0 -2
  98. data/spec/{lib/granite → granite}/form/model/primary_spec.rb +1 -1
  99. data/spec/{lib/granite → granite}/form/model/representation_spec.rb +0 -0
  100. data/spec/{lib/granite → granite}/form/model/scopes_spec.rb +0 -0
  101. data/spec/{lib/granite → granite}/form/model/validations/associated_spec.rb +2 -4
  102. data/spec/{lib/granite → granite}/form/model/validations/nested_spec.rb +57 -15
  103. data/spec/{lib/granite → granite}/form/model/validations_spec.rb +0 -0
  104. data/spec/{lib/granite → granite}/form/model_spec.rb +0 -0
  105. data/spec/granite/form/types/active_support/time_zone_spec.rb +24 -0
  106. data/spec/granite/form/types/array_spec.rb +13 -0
  107. data/spec/granite/form/types/big_decimal_spec.rb +19 -0
  108. data/spec/granite/form/types/boolean_spec.rb +21 -0
  109. data/spec/granite/form/types/date_spec.rb +18 -0
  110. data/spec/granite/form/types/date_time_spec.rb +20 -0
  111. data/spec/granite/form/types/float_spec.rb +19 -0
  112. data/spec/granite/form/types/hash_with_action_controller_parameters_spec.rb +22 -0
  113. data/spec/granite/form/types/integer_spec.rb +18 -0
  114. data/spec/granite/form/types/object_spec.rb +40 -0
  115. data/spec/granite/form/types/string_spec.rb +13 -0
  116. data/spec/granite/form/types/time_spec.rb +31 -0
  117. data/spec/granite/form/types/uuid_spec.rb +21 -0
  118. data/spec/{lib/granite → granite}/form_spec.rb +0 -0
  119. data/spec/spec_helper.rb +0 -15
  120. data/spec/support/active_record.rb +20 -0
  121. data/spec/{shared → support/shared}/nested_attribute_examples.rb +3 -21
  122. data/spec/support/shared/type_examples.rb +7 -0
  123. metadata +173 -123
  124. data/.github/workflows/main.yml +0 -29
  125. data/gemfiles/rails.4.2.gemfile +0 -15
  126. data/lib/granite/form/model/callbacks.rb +0 -72
  127. data/lib/granite/form/model/lifecycle.rb +0 -309
  128. data/spec/lib/granite/form/model/associations/nested_attributes_spec.rb +0 -119
  129. data/spec/lib/granite/form/model/associations/references_many_spec.rb +0 -572
  130. data/spec/lib/granite/form/model/associations/references_one_spec.rb +0 -445
  131. data/spec/lib/granite/form/model/callbacks_spec.rb +0 -337
  132. data/spec/lib/granite/form/model/lifecycle_spec.rb +0 -356
  133. data/spec/lib/granite/form/model/typecasting_spec.rb +0 -193
@@ -1,445 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Granite::Form::Model::Associations::ReferencesOne do
4
- before do
5
- stub_class(:author, ActiveRecord::Base) do
6
- validates :name, presence: true
7
- end
8
-
9
- stub_model(:book) do
10
- include Granite::Form::Model::Persistence
11
- include Granite::Form::Model::Associations
12
-
13
- attribute :title, String
14
- references_one :author
15
- end
16
- end
17
-
18
- let(:author) { Author.create!(name: 'Johny') }
19
- let(:other) { Author.create!(name: 'Other') }
20
- let(:book) { Book.new }
21
- let(:association) { book.association(:author) }
22
-
23
- let(:existing_book) { Book.instantiate title: 'My Life', author_id: author.id }
24
- let(:existing_association) { existing_book.association(:author) }
25
-
26
- describe 'book#association' do
27
- specify { expect(association).to be_a described_class }
28
- specify { expect(association).to eq(book.association(:author)) }
29
- end
30
-
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
307
- end
308
-
309
- describe '#target' do
310
- specify { expect(association.target).to be_nil }
311
- specify { expect(existing_association.target).to eq(existing_book.author) }
312
- end
313
-
314
- describe '#loaded?' do
315
- let(:new_author) { Author.create(name: 'Morty') }
316
-
317
- specify { expect(association.loaded?).to eq(false) }
318
- specify { expect { association.target }.to change { association.loaded? }.to(true) }
319
- specify { expect { association.replace(new_author) }.to change { association.loaded? }.to(true) }
320
- specify { expect { association.replace(nil) }.to change { association.loaded? }.to(true) }
321
- specify { expect { existing_association.replace(new_author) }.to change { existing_association.loaded? }.to(true) }
322
- specify { expect { existing_association.replace(nil) }.to change { existing_association.loaded? }.to(true) }
323
- end
324
-
325
- describe '#reload' do
326
- specify { expect(association.reload).to be_nil }
327
-
328
- specify { expect(existing_association.reload).to be_a Author }
329
- specify { expect(existing_association.reload).to be_persisted }
330
-
331
- context do
332
- before { existing_association.reader.name = 'New' }
333
- specify do
334
- expect { existing_association.reload }
335
- .to change { existing_association.reader.name }
336
- .from('New').to('Johny')
337
- end
338
- end
339
- end
340
-
341
- describe '#reader' do
342
- specify { expect(association.reader).to be_nil }
343
-
344
- specify { expect(existing_association.reader).to be_a Author }
345
- specify { expect(existing_association.reader).to be_persisted }
346
- end
347
-
348
- describe '#default' do
349
- before { Book.references_one :author, default: ->(_book) { author.id } }
350
- let(:existing_book) { Book.instantiate title: 'My Life' }
351
-
352
- specify { expect(association.target).to eq(author) }
353
- specify { expect { association.replace(other) }.to change { association.target }.to(other) }
354
- specify { expect { association.replace(nil) }.to change { association.target }.to be_nil }
355
-
356
- specify { expect(existing_association.target).to be_nil }
357
- specify { expect { existing_association.replace(other) }.to change { existing_association.target }.to(other) }
358
- specify { expect { existing_association.replace(nil) }.not_to change { existing_association.target } }
359
- end
360
-
361
- describe '#writer' do
362
- context 'new owner' do
363
- let(:new_author) { Author.new(name: 'Morty') }
364
-
365
- let(:book) do
366
- Book.new.tap do |book|
367
- book.send(:mark_persisted!)
368
- end
369
- end
370
-
371
- specify do
372
- expect { association.writer(nil) }
373
- .not_to change { book.author_id }
374
- end
375
- specify do
376
- expect { association.writer(new_author) }
377
- .to change { muffle(NoMethodError) { association.reader.name } }
378
- .from(nil).to('Morty')
379
- end
380
- specify do
381
- expect { association.writer(new_author) }
382
- .not_to change { book.author_id }.from(nil)
383
- end
384
- end
385
-
386
- context 'persisted owner' do
387
- let(:new_author) { Author.create(name: 'Morty') }
388
-
389
- specify do
390
- expect { association.writer(stub_model(:dummy).new) }
391
- .to raise_error Granite::Form::AssociationTypeMismatch
392
- end
393
-
394
- specify { expect(association.writer(nil)).to be_nil }
395
- specify { expect(association.writer(new_author)).to eq(new_author) }
396
- specify do
397
- expect { association.writer(nil) }
398
- .not_to change { book.read_attribute(:author_id) }
399
- end
400
- specify do
401
- expect { association.writer(new_author) }
402
- .to change { association.reader.try(:attributes) }.from(nil).to('id' => 1, 'name' => 'Morty')
403
- end
404
- specify do
405
- expect { association.writer(new_author) }
406
- .to change { book.read_attribute(:author_id) }
407
- end
408
-
409
- context do
410
- before do
411
- stub_class(:dummy, ActiveRecord::Base) do
412
- self.table_name = :authors
413
- end
414
- end
415
-
416
- specify do
417
- expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer(Dummy.new) } }
418
- .not_to change { existing_book.read_attribute(:author_id) }
419
- end
420
- specify do
421
- expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer(Dummy.new) } }
422
- .not_to change { existing_association.reader }
423
- end
424
- end
425
-
426
- specify { expect(existing_association.writer(nil)).to be_nil }
427
- specify { expect(existing_association.writer(new_author)).to eq(new_author) }
428
- specify do
429
- expect { existing_association.writer(nil) }
430
- .to change { existing_book.read_attribute(:author_id) }
431
- .from(author.id).to(nil)
432
- end
433
- specify do
434
- 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')
437
- end
438
- specify do
439
- expect { existing_association.writer(new_author) }
440
- .to change { existing_book.read_attribute(:author_id) }
441
- .from(author.id).to(new_author.id)
442
- end
443
- end
444
- end
445
- end