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,572 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Granite::Form::Model::Associations::ReferencesMany do
4
- before do
5
- stub_model(:dummy)
6
- stub_class(:author, ActiveRecord::Base) do
7
- scope :name_starts_with_a, -> { where('name LIKE "a%"') }
8
-
9
- validates :name, presence: true
10
- end
11
-
12
- stub_model(:book) do
13
- include Granite::Form::Model::Persistence
14
- include Granite::Form::Model::Associations
15
-
16
- attribute :title, String
17
- references_many :authors
18
- end
19
- end
20
-
21
- let(:author) { Author.create!(name: 'Rick') }
22
- let(:other) { Author.create!(name: 'Ben') }
23
-
24
- let(:book) { Book.new }
25
- let(:association) { book.association(:authors) }
26
-
27
- let(:existing_book) { Book.instantiate title: 'Genesis', author_ids: [author.id] }
28
- let(:existing_association) { existing_book.association(:authors) }
29
-
30
- describe 'book#association' do
31
- specify { expect(association).to be_a described_class }
32
- specify { expect(association).to eq(book.association(:authors)) }
33
- end
34
-
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
360
- end
361
-
362
- describe '#scope' do
363
- specify { expect(association.scope).to be_a ActiveRecord::Relation }
364
- specify { expect(association.scope).to respond_to(:where) }
365
- specify { expect(association.scope).to respond_to(:name_starts_with_a) }
366
- end
367
-
368
- describe '#target' do
369
- specify { expect(association.target).to eq([]) }
370
- specify { expect(existing_association.target).to eq(existing_book.authors) }
371
- specify { expect { association.concat author }.to change { association.target.count }.to(1) }
372
- end
373
-
374
- describe '#default' do
375
- before { Book.references_many :authors, default: ->(_book) { author.id } }
376
- let(:existing_book) { Book.instantiate title: 'Genesis' }
377
-
378
- specify { expect(association.target).to eq([author]) }
379
- specify { expect { association.replace([other]) }.to change { association.target }.to([other]) }
380
- specify { expect { association.replace([]) }.to change { association.target }.to eq([]) }
381
-
382
- specify { expect(existing_association.target).to eq([]) }
383
- specify { expect { existing_association.replace([other]) }.to change { existing_association.target }.to([other]) }
384
- specify { expect { existing_association.replace([]) }.not_to change { existing_association.target } }
385
- end
386
-
387
- describe '#loaded?' do
388
- specify { expect(association.loaded?).to eq(false) }
389
- specify { expect { association.target }.to change { association.loaded? }.to(true) }
390
- specify { expect { association.replace([]) }.to change { association.loaded? }.to(true) }
391
- specify { expect { existing_association.replace([]) }.to change { existing_association.loaded? }.to(true) }
392
- end
393
-
394
- describe '#reload' do
395
- specify { expect(association.reload).to eq([]) }
396
-
397
- specify { expect(existing_association.reload).to eq(existing_book.authors) }
398
-
399
- context do
400
- before { existing_association.reader.last.name = 'Conan' }
401
- specify do
402
- expect { existing_association.reload }
403
- .to change { existing_association.reader.map(&:name) }
404
- .from(['Conan']).to(['Rick'])
405
- end
406
- end
407
- end
408
-
409
- describe '#reader' do
410
- specify { expect(association.reader).to eq([]) }
411
- specify { expect(association.reader).to be_a Granite::Form::Model::Associations::PersistenceAdapters::ActiveRecord::ReferencedProxy }
412
-
413
- specify { expect(existing_association.reader.first).to be_a Author }
414
- specify { expect(existing_association.reader.first).to be_persisted }
415
-
416
- context do
417
- before { association.concat author }
418
- specify { expect(association.reader.last).to be_a Author }
419
- specify { expect(association.reader.size).to eq(1) }
420
- specify { expect(association.reader(true)).to eq([author]) }
421
- end
422
-
423
- context do
424
- before { existing_association.concat other }
425
- specify { expect(existing_association.reader.size).to eq(2) }
426
- specify { expect(existing_association.reader.last.name).to eq('Ben') }
427
- specify { expect(existing_association.reader(true).size).to eq(2) }
428
- specify { expect(existing_association.reader(true).last.name).to eq('Ben') }
429
- end
430
-
431
- context 'proxy missing method delection' do
432
- specify { expect(existing_association.reader).to respond_to(:where) }
433
- specify { expect(existing_association.reader).to respond_to(:name_starts_with_a) }
434
- end
435
- end
436
-
437
- describe '#writer' do
438
- let(:new_author1) { Author.create!(name: 'John') }
439
- let(:new_author2) { Author.create!(name: 'Adam') }
440
- let(:new_author3) { Author.new(name: 'Jane') }
441
-
442
- specify do
443
- expect { association.writer([Dummy.new]) }
444
- .to raise_error Granite::Form::AssociationTypeMismatch
445
- end
446
-
447
- specify { expect { association.writer(nil) }.to raise_error NoMethodError }
448
- specify { expect { association.writer(new_author1) }.to raise_error NoMethodError }
449
- specify { expect(association.writer([])).to eq([]) }
450
-
451
- specify { expect(association.writer([new_author1])).to eq([new_author1]) }
452
- specify do
453
- expect { association.writer([new_author1]) }
454
- .to change { association.reader.map(&:name) }.from([]).to(['John'])
455
- end
456
- specify do
457
- expect { association.writer([new_author1]) }
458
- .to change { book.read_attribute(:author_ids) }
459
- .from([]).to([new_author1.id])
460
- end
461
-
462
- specify do
463
- expect { existing_association.writer([new_author1, Dummy.new, new_author2]) }
464
- .to raise_error Granite::Form::AssociationTypeMismatch
465
- end
466
- specify do
467
- expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer([new_author1, Dummy.new, new_author2]) } }
468
- .not_to change { existing_book.read_attribute(:author_ids) }
469
- end
470
- specify do
471
- expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.writer([new_author1, Dummy.new, new_author2]) } }
472
- .not_to change { existing_association.reader }
473
- end
474
-
475
- specify { expect { existing_association.writer(nil) }.to raise_error NoMethodError }
476
- specify do
477
- expect { muffle(NoMethodError) { existing_association.writer(nil) } }
478
- .not_to change { existing_book.read_attribute(:author_ids) }
479
- end
480
- specify do
481
- expect { muffle(NoMethodError) { existing_association.writer(nil) } }
482
- .not_to change { existing_association.reader }
483
- end
484
-
485
- specify { expect(existing_association.writer([])).to eq([]) }
486
- specify do
487
- expect { existing_association.writer([]) }
488
- .to change { existing_book.read_attribute(:author_ids) }.to([])
489
- end
490
- specify do
491
- expect { existing_association.writer([]) }
492
- .to change { existing_association.reader }.from([author]).to([])
493
- end
494
-
495
- specify { expect(existing_association.writer([new_author1, new_author2])).to eq([new_author1, new_author2]) }
496
- specify do
497
- expect { existing_association.writer([new_author1, new_author2]) }
498
- .to change { existing_association.reader.map(&:name) }
499
- .from(['Rick']).to(%w[John Adam])
500
- end
501
- specify do
502
- expect { existing_association.writer([new_author1, new_author2]) }
503
- .to change { existing_book.read_attribute(:author_ids) }
504
- .from([author.id]).to([new_author1.id, new_author2.id])
505
- end
506
-
507
- specify do
508
- expect { existing_association.writer([new_author3]) }
509
- .to change { existing_association.target }.from([author]).to([new_author3])
510
- end
511
- specify do
512
- expect { existing_association.writer([new_author3]) }
513
- .to change { existing_book.read_attribute(:author_ids) }
514
- .from([author.id]).to([nil])
515
- end
516
- end
517
-
518
- describe '#concat' do
519
- let(:new_author1) { Author.create!(name: 'John') }
520
- let(:new_author2) { Author.create!(name: 'Adam') }
521
-
522
- specify do
523
- expect { association.concat(Dummy.new) }
524
- .to raise_error Granite::Form::AssociationTypeMismatch
525
- end
526
-
527
- specify { expect { association.concat(nil) }.to raise_error Granite::Form::AssociationTypeMismatch }
528
- specify { expect(association.concat([])).to eq([]) }
529
- specify { expect(existing_association.concat([])).to eq(existing_book.authors) }
530
- specify { expect(existing_association.concat).to eq(existing_book.authors) }
531
-
532
- specify { expect(association.concat(new_author1)).to eq([new_author1]) }
533
- specify do
534
- expect { association.concat(new_author1) }
535
- .to change { association.reader.map(&:name) }.from([]).to(['John'])
536
- end
537
- specify do
538
- expect { association.concat(new_author1) }
539
- .to change { book.read_attribute(:author_ids) }.from([]).to([1])
540
- end
541
-
542
- specify do
543
- expect { existing_association.concat(new_author1, Dummy.new, new_author2) }
544
- .to raise_error Granite::Form::AssociationTypeMismatch
545
- end
546
- specify do
547
- expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.concat(new_author1, Dummy.new, new_author2) } }
548
- .to change { existing_book.read_attribute(:author_ids) }
549
- .from([author.id]).to([author.id, new_author1.id])
550
- end
551
- specify do
552
- expect { muffle(Granite::Form::AssociationTypeMismatch) { existing_association.concat(new_author1, Dummy.new, new_author2) } }
553
- .to change { existing_association.reader.map(&:name) }
554
- .from(['Rick']).to(%w[Rick John])
555
- end
556
-
557
- specify do
558
- expect(existing_association.concat(new_author1, new_author2))
559
- .to eq([author, new_author1, new_author2])
560
- end
561
- specify do
562
- expect { existing_association.concat([new_author1, new_author2]) }
563
- .to change { existing_association.reader.map(&:name) }
564
- .from(['Rick']).to(%w[Rick John Adam])
565
- end
566
- specify do
567
- expect { existing_association.concat([new_author1, new_author2]) }
568
- .to change { existing_book.read_attribute(:author_ids) }
569
- .from([author.id]).to([author.id, new_author1.id, new_author2.id])
570
- end
571
- end
572
- end