iknow_view_models 2.9.0 → 3.0.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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/iknow_view_models.gemspec +1 -1
  3. data/lib/iknow_view_models/version.rb +1 -1
  4. data/lib/view_model/active_record/association_data.rb +206 -92
  5. data/lib/view_model/active_record/association_manipulation.rb +22 -12
  6. data/lib/view_model/active_record/cache/cacheable_view.rb +3 -13
  7. data/lib/view_model/active_record/cache.rb +2 -2
  8. data/lib/view_model/active_record/cloner.rb +11 -11
  9. data/lib/view_model/active_record/controller.rb +0 -2
  10. data/lib/view_model/active_record/update_context.rb +21 -3
  11. data/lib/view_model/active_record/update_data.rb +43 -45
  12. data/lib/view_model/active_record/update_operation.rb +265 -153
  13. data/lib/view_model/active_record/visitor.rb +9 -6
  14. data/lib/view_model/active_record.rb +94 -74
  15. data/lib/view_model/after_transaction_runner.rb +3 -18
  16. data/lib/view_model/changes.rb +24 -16
  17. data/lib/view_model/config.rb +6 -2
  18. data/lib/view_model/deserialization_error.rb +31 -0
  19. data/lib/view_model/deserialize_context.rb +2 -6
  20. data/lib/view_model/error_view.rb +6 -5
  21. data/lib/view_model/record/attribute_data.rb +11 -6
  22. data/lib/view_model/record.rb +44 -24
  23. data/lib/view_model/serialize_context.rb +2 -63
  24. data/lib/view_model.rb +17 -8
  25. data/shell.nix +1 -1
  26. data/test/helpers/arvm_test_utilities.rb +6 -0
  27. data/test/helpers/controller_test_helpers.rb +5 -3
  28. data/test/helpers/viewmodel_spec_helpers.rb +63 -52
  29. data/test/unit/view_model/access_control_test.rb +88 -37
  30. data/test/unit/view_model/active_record/belongs_to_test.rb +110 -178
  31. data/test/unit/view_model/active_record/cache_test.rb +3 -2
  32. data/test/unit/view_model/active_record/cloner_test.rb +1 -1
  33. data/test/unit/view_model/active_record/controller_test.rb +12 -20
  34. data/test/unit/view_model/active_record/has_many_test.rb +540 -316
  35. data/test/unit/view_model/active_record/has_many_through_poly_test.rb +12 -15
  36. data/test/unit/view_model/active_record/has_many_through_test.rb +15 -58
  37. data/test/unit/view_model/active_record/has_one_test.rb +288 -135
  38. data/test/unit/view_model/active_record/poly_test.rb +0 -1
  39. data/test/unit/view_model/active_record/shared_test.rb +21 -39
  40. data/test/unit/view_model/active_record/version_test.rb +3 -2
  41. data/test/unit/view_model/active_record_test.rb +5 -63
  42. data/test/unit/view_model/callbacks_test.rb +1 -0
  43. data/test/unit/view_model/record_test.rb +0 -32
  44. data/test/unit/view_model/traversal_context_test.rb +13 -12
  45. metadata +5 -8
  46. data/test/unit/view_model/active_record/optional_attribute_view_test.rb +0 -58
@@ -1,5 +1,6 @@
1
1
  require_relative "../../../helpers/arvm_test_utilities.rb"
2
2
  require_relative "../../../helpers/arvm_test_models.rb"
3
+ require_relative '../../../helpers/viewmodel_spec_helpers.rb'
3
4
 
4
5
  require "minitest/autorun"
5
6
 
@@ -7,122 +8,57 @@ require "view_model/active_record"
7
8
 
8
9
  class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
9
10
  include ARVMTestUtilities
10
-
11
- module WithLabel
12
- def before_all
13
- super
14
-
15
- build_viewmodel(:Label) do
16
- define_schema do |t|
17
- t.string :text
18
- end
19
-
20
- define_model do
21
- has_one :parent, inverse_of: :label
22
- end
23
-
24
- define_viewmodel do
25
- attributes :text
26
- end
27
- end
28
- end
29
- end
30
-
31
- module WithParent
32
- def before_all
33
- super
34
-
35
- build_viewmodel(:Parent) do
36
- define_schema do |t|
37
- t.string :name
38
- t.references :label, foreign_key: true
39
- end
40
-
41
- define_model do
42
- belongs_to :label, inverse_of: :parent, dependent: :destroy
43
- end
44
-
45
- define_viewmodel do
46
- attributes :name
47
- associations :label
48
- end
49
- end
50
- end
51
- end
52
-
53
- module WithOwner
54
- def before_all
55
- super
56
-
57
- build_viewmodel(:Owner) do
58
- define_schema do |t|
59
- t.integer :deleted_id
60
- t.integer :ignored_id
61
- end
62
-
63
- define_model do
64
- belongs_to :deleted, class_name: Label.name, dependent: :delete
65
- belongs_to :ignored, class_name: Label.name
66
- end
67
-
68
- define_viewmodel do
69
- associations :deleted, :ignored
70
- end
71
- end
72
- end
73
- end
74
-
75
- include WithLabel
76
- include WithParent
11
+ extend Minitest::Spec::DSL
12
+ include ViewModelSpecHelpers::ParentAndBelongsToChild
77
13
 
78
14
  def setup
79
15
  super
80
16
 
81
17
  # TODO make a `has_list?` that allows a parent to set all children as an array
82
- @parent1 = Parent.new(name: "p1",
83
- label: Label.new(text: "p1l"))
84
- @parent1.save!
18
+ @model1 = model_class.new(name: "p1",
19
+ child: child_model_class.new(name: "p1l"))
20
+ @model1.save!
85
21
 
86
- @parent2 = Parent.new(name: "p2",
87
- label: Label.new(text: "p2l"))
22
+ @model2 = model_class.new(name: "p2",
23
+ child: child_model_class.new(name: "p2l"))
88
24
 
89
- @parent2.save!
25
+ @model2.save!
90
26
 
91
27
  enable_logging!
92
28
  end
93
29
 
94
30
  def test_serialize_view
95
- view, _refs = serialize_with_references(ParentView.new(@parent1))
31
+ view, _refs = serialize_with_references(ModelView.new(@model1))
96
32
 
97
- assert_equal({ "_type" => "Parent",
33
+ assert_equal({ "_type" => "Model",
98
34
  "_version" => 1,
99
- "id" => @parent1.id,
100
- "name" => @parent1.name,
101
- "label" => { "_type" => "Label",
35
+ "id" => @model1.id,
36
+ "name" => @model1.name,
37
+ "child" => { "_type" => "Child",
102
38
  "_version" => 1,
103
- "id" => @parent1.label.id,
104
- "text" => @parent1.label.text },
39
+ "id" => @model1.child.id,
40
+ "name" => @model1.child.name },
105
41
  },
106
42
  view)
107
43
  end
108
44
 
109
45
  def test_loading_batching
110
46
  log_queries do
111
- serialize(ParentView.load)
47
+ serialize(ModelView.load)
112
48
  end
113
49
 
114
- assert_equal(['Parent Load', 'Label Load'],
50
+ assert_equal(['Model Load', 'Child Load'],
115
51
  logged_load_queries)
116
52
  end
117
53
 
118
54
  def test_create_from_view
119
55
  view = {
120
- "_type" => "Parent",
56
+ "_type" => "Model",
121
57
  "name" => "p",
122
- "label" => { "_type" => "Label", "text" => "l" },
58
+ "child" => { "_type" => "Child", "name" => "l" },
123
59
  }
124
60
 
125
- pv = ParentView.deserialize_from_view(view)
61
+ pv = ModelView.deserialize_from_view(view)
126
62
  p = pv.model
127
63
 
128
64
  assert(!p.changed?)
@@ -130,185 +66,181 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
130
66
 
131
67
  assert_equal("p", p.name)
132
68
 
133
- assert(p.label.present?)
134
- assert_equal("l", p.label.text)
69
+ assert(p.child.present?)
70
+ assert_equal("l", p.child.name)
135
71
  end
136
72
 
137
73
  def test_create_belongs_to_nil
138
- view = { '_type' => 'Parent', 'name' => 'p', 'label' => nil }
139
- pv = ParentView.deserialize_from_view(view)
140
- assert_nil(pv.model.label)
74
+ view = { '_type' => 'Model', 'name' => 'p', 'child' => nil }
75
+ pv = ModelView.deserialize_from_view(view)
76
+ assert_nil(pv.model.child)
141
77
  end
142
78
 
143
79
  def test_create_invalid_child_type
144
- view = { '_type' => 'Parent', 'name' => 'p', 'label' => { '_type' => 'Parent', 'name' => 'q' } }
80
+ view = { '_type' => 'Model', 'name' => 'p', 'child' => { '_type' => 'Model', 'name' => 'q' } }
145
81
  assert_raises(ViewModel::DeserializationError::InvalidAssociationType) do
146
- ParentView.deserialize_from_view(view)
82
+ ModelView.deserialize_from_view(view)
147
83
  end
148
84
  end
149
85
 
150
86
  def test_belongs_to_create
151
- @parent1.update(label: nil)
87
+ @model1.update(child: nil)
152
88
 
153
- alter_by_view!(ParentView, @parent1) do |view, refs|
154
- view['label'] = { '_type' => 'Label', 'text' => 'cheese' }
89
+ alter_by_view!(ModelView, @model1) do |view, refs|
90
+ view['child'] = { '_type' => 'Child', 'name' => 'cheese' }
155
91
  end
156
92
 
157
- assert_equal('cheese', @parent1.label.text)
93
+ assert_equal('cheese', @model1.child.name)
158
94
  end
159
95
 
160
96
  def test_belongs_to_replace
161
- old_label = @parent1.label
97
+ old_child = @model1.child
162
98
 
163
- alter_by_view!(ParentView, @parent1) do |view, refs|
164
- view['label'] = { '_type' => 'Label', 'text' => 'cheese' }
99
+ alter_by_view!(ModelView, @model1) do |view, refs|
100
+ view['child'] = { '_type' => 'Child', 'name' => 'cheese' }
165
101
  end
166
102
 
167
- assert_equal('cheese', @parent1.label.text)
168
- assert(Label.where(id: old_label).blank?)
103
+ assert_equal('cheese', @model1.child.name)
104
+ assert(Child.where(id: old_child).blank?)
169
105
  end
170
106
 
171
107
  def test_belongs_to_move_and_replace
172
- old_p1_label = @parent1.label
173
- old_p2_label = @parent2.label
108
+ old_p1_child = @model1.child
109
+ old_p2_child = @model2.child
174
110
 
175
- set_by_view!(ParentView, [@parent1, @parent2]) do |(p1, p2), refs|
176
- p1['label'] = nil
177
- p2['label'] = update_hash_for(LabelView, old_p1_label)
111
+ set_by_view!(ModelView, [@model1, @model2]) do |(p1, p2), refs|
112
+ p1['child'] = nil
113
+ p2['child'] = update_hash_for(ChildView, old_p1_child)
178
114
  end
179
115
 
180
- assert(@parent1.label.blank?, 'l1 label reference removed')
181
- assert_equal(old_p1_label, @parent2.label, 'p2 has label from p1')
182
- assert(Label.where(id: old_p2_label).blank?, 'p2 old label deleted')
116
+ assert(@model1.child.blank?, 'l1 child reference removed')
117
+ assert_equal(old_p1_child, @model2.child, 'p2 has child from p1')
118
+ assert(Child.where(id: old_p2_child).blank?, 'p2 old child deleted')
183
119
  end
184
120
 
185
121
  def test_belongs_to_swap
186
- old_p1_label = @parent1.label
187
- old_p2_label = @parent2.label
122
+ old_p1_child = @model1.child
123
+ old_p2_child = @model2.child
188
124
 
189
- alter_by_view!(ParentView, [@parent1, @parent2]) do |(p1, p2), refs|
190
- p1['label'] = update_hash_for(LabelView, old_p2_label)
191
- p2['label'] = update_hash_for(LabelView, old_p1_label)
125
+ alter_by_view!(ModelView, [@model1, @model2]) do |(p1, p2), refs|
126
+ p1['child'] = update_hash_for(ChildView, old_p2_child)
127
+ p2['child'] = update_hash_for(ChildView, old_p1_child)
192
128
  end
193
129
 
194
- assert_equal(old_p2_label, @parent1.label, 'p1 has label from p2')
195
- assert_equal(old_p1_label, @parent2.label, 'p2 has label from p1')
130
+ assert_equal(old_p2_child, @model1.child, 'p1 has child from p2')
131
+ assert_equal(old_p1_child, @model2.child, 'p2 has child from p1')
196
132
  end
197
133
 
198
134
  def test_moved_child_is_not_delete_checked
199
135
  # move from p1 to p3
200
- d_context = ParentView.new_deserialize_context
136
+ d_context = ModelView.new_deserialize_context
201
137
 
202
- target_label = Label.create
203
- from_parent = Parent.create(name: 'from', label: target_label)
204
- to_parent = Parent.create(name: 'p3')
138
+ target_child = Child.create
139
+ from_model = Model.create(name: 'from', child: target_child)
140
+ to_model = Model.create(name: 'p3')
205
141
 
206
142
  alter_by_view!(
207
- ParentView, [from_parent, to_parent],
143
+ ModelView, [from_model, to_model],
208
144
  deserialize_context: d_context
209
145
  ) do |(from, to), refs|
210
- from['label'] = nil
211
- to['label'] = update_hash_for(LabelView, target_label)
146
+ from['child'] = nil
147
+ to['child'] = update_hash_for(ChildView, target_child)
212
148
  end
213
149
 
214
- assert_equal(target_label, to_parent.label, 'target label moved')
215
- assert_equal([ViewModel::Reference.new(ParentView, from_parent.id),
216
- ViewModel::Reference.new(ParentView, to_parent.id)],
150
+ assert_equal(target_child, to_model.child, 'target child moved')
151
+ assert_equal([ViewModel::Reference.new(ModelView, from_model.id),
152
+ ViewModel::Reference.new(ModelView, to_model.id)],
217
153
  d_context.valid_edit_refs,
218
- "only parents are checked for change; child was not")
154
+ "only models are checked for change; child was not")
219
155
  end
220
156
 
221
157
  def test_implicit_release_invalid_belongs_to
222
- taken_label_ref = update_hash_for(LabelView, @parent1.label)
158
+ taken_child_ref = update_hash_for(ChildView, @model1.child)
223
159
  assert_raises(ViewModel::DeserializationError::ParentNotFound) do
224
- ParentView.deserialize_from_view(
225
- [{ '_type' => 'Parent',
160
+ ModelView.deserialize_from_view(
161
+ [{ '_type' => 'Model',
226
162
  'name' => 'newp',
227
- 'label' => taken_label_ref }])
163
+ 'child' => taken_child_ref }])
228
164
  end
229
165
  end
230
166
 
231
167
  class GCTests < ActiveSupport::TestCase
232
168
  include ARVMTestUtilities
233
- include WithLabel
234
- include WithOwner
235
- include WithParent
169
+ include ViewModelSpecHelpers::ParentAndBelongsToChild
170
+
171
+ def model_attributes
172
+ super.merge(
173
+ schema: ->(t) do
174
+ t.integer :deleted_child_id
175
+ t.integer :ignored_child_id
176
+ end,
177
+ model: ->(m) do
178
+ belongs_to :deleted_child, class_name: Child.name, dependent: :delete
179
+ belongs_to :ignored_child, class_name: Child.name
180
+ end,
181
+ viewmodel: ->(v) do
182
+ associations :deleted_child, :ignored_child
183
+ end)
184
+ end
236
185
 
237
186
  # test belongs_to garbage collection - dependent: delete_all
238
187
  def test_gc_dependent_delete_all
239
- owner = Owner.create(deleted: Label.new(text: 'one'))
240
- old_label = owner.deleted
188
+ model = model_class.create(deleted_child: Child.new(name: 'one'))
189
+ old_child = model.deleted_child
241
190
 
242
- alter_by_view!(OwnerView, owner) do |ov, refs|
243
- ov['deleted'] = { '_type' => 'Label', 'text' => 'two' }
191
+ alter_by_view!(ModelView, model) do |ov, _refs|
192
+ ov['deleted_child'] = { '_type' => 'Child', 'name' => 'two' }
244
193
  end
245
194
 
246
- assert_equal('two', owner.deleted.text)
247
- refute_equal(old_label, owner.deleted)
248
- assert(Label.where(id: old_label.id).blank?)
195
+ assert_equal('two', model.deleted_child.name)
196
+ refute_equal(old_child, model.deleted_child)
197
+ assert(Child.where(id: old_child.id).blank?)
249
198
  end
250
199
 
251
200
  def test_no_gc_dependent_ignore
252
- owner = Owner.create(ignored: Label.new(text: "one"))
253
- old_label = owner.ignored
201
+ model = model_class.create(ignored_child: Child.new(name: "one"))
202
+ old_child = model.ignored_child
254
203
 
255
- alter_by_view!(OwnerView, owner) do |ov, refs|
256
- ov['ignored'] = { '_type' => 'Label', 'text' => 'two' }
204
+ alter_by_view!(ModelView, model) do |ov, _refs|
205
+ ov['ignored_child'] = { '_type' => 'Child', 'name' => 'two' }
257
206
  end
258
- assert_equal('two', owner.ignored.text)
259
- refute_equal(old_label, owner.ignored)
260
- assert_equal(1, Label.where(id: old_label.id).count)
207
+ assert_equal('two', model.ignored_child.name)
208
+ refute_equal(old_child, model.ignored_child)
209
+ assert_equal(1, Child.where(id: old_child.id).count)
261
210
  end
262
211
  end
263
212
 
264
213
  class RenamedTest < ActiveSupport::TestCase
265
214
  include ARVMTestUtilities
266
- include WithLabel
267
-
268
- def before_all
269
- super
270
-
271
- build_viewmodel(:Parent) do
272
- define_schema do |t|
273
- t.string :name
274
- t.references :label, foreign_key: true
275
- end
276
-
277
- define_model do
278
- belongs_to :label, inverse_of: :parent, dependent: :destroy
279
- end
215
+ include ViewModelSpecHelpers::ParentAndBelongsToChild
280
216
 
281
- define_viewmodel do
282
- attributes :name
283
- association :label, as: :something_else
284
- end
285
- end
217
+ def subject_association_features
218
+ { as: :something_else }
286
219
  end
287
220
 
288
221
  def setup
289
222
  super
290
223
 
291
- @parent = Parent.create(name: 'p1', label: Label.new(text: 'l1'))
224
+ @model = model_class.create(name: 'p1', child: child_model_class.new(name: 'l1'))
292
225
 
293
226
  enable_logging!
294
227
  end
295
228
 
296
229
  def test_dependencies
297
- root_updates, _ref_updates = ViewModel::ActiveRecord::UpdateData.parse_hashes([{ '_type' => 'Parent', 'something_else' => nil }])
298
- assert_equal(DeepPreloader::Spec.new('label' => DeepPreloader::Spec.new), root_updates.first.preload_dependencies)
299
- assert_equal({ 'something_else' => {} }, root_updates.first.updated_associations)
230
+ root_updates, _ref_updates = ViewModel::ActiveRecord::UpdateData.parse_hashes([{ '_type' => 'Model', 'something_else' => nil }])
231
+ assert_equal(DeepPreloader::Spec.new('child' => DeepPreloader::Spec.new), root_updates.first.preload_dependencies)
300
232
  end
301
233
 
302
234
  def test_renamed_roundtrip
303
- alter_by_view!(ParentView, @parent) do |view, refs|
304
- assert_equal({ 'id' => @parent.label.id,
305
- '_type' => 'Label',
235
+ alter_by_view!(ModelView, @model) do |view, refs|
236
+ assert_equal({ 'id' => @model.child.id,
237
+ '_type' => 'Child',
306
238
  '_version' => 1,
307
- 'text' => 'l1' },
239
+ 'name' => 'l1' },
308
240
  view['something_else'])
309
- view['something_else']['text'] = 'new l1 text'
241
+ view['something_else']['name'] = 'new l1 name'
310
242
  end
311
- assert_equal('new l1 text', @parent.label.text)
243
+ assert_equal('new l1 name', @model.child.name)
312
244
  end
313
245
  end
314
246
 
@@ -353,7 +285,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
353
285
  end
354
286
 
355
287
 
356
- # Do we support replacing a node in the tree and reparenting its children
288
+ # Do we support replacing a node in the tree and remodeling its children
357
289
  # back to it? In theory we want to, but currently we don't: the child node
358
290
  # is unresolvable.
359
291
 
@@ -41,7 +41,7 @@ class ViewModel::ActiveRecord
41
41
  schema: ->(t) { t.references :shared, foreign_key: true },
42
42
  model: ->(_) { belongs_to :shared, inverse_of: :models },
43
43
  viewmodel: ->(_) {
44
- association :shared, shared: true, optional: false
44
+ association :shared
45
45
  cacheable!
46
46
  }
47
47
  )
@@ -63,6 +63,7 @@ class ViewModel::ActiveRecord
63
63
  end
64
64
 
65
65
  define_viewmodel do
66
+ root!
66
67
  attributes :name
67
68
  cacheable!(cache_group: shared_cache_group)
68
69
  end
@@ -326,7 +327,7 @@ class ViewModel::ActiveRecord
326
327
  end
327
328
 
328
329
  describe "with a non-cacheable shared child" do
329
- include ViewModelSpecHelpers::ParentAndSharedChild
330
+ include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
330
331
  def model_attributes
331
332
  super.merge(viewmodel: ->(_) { cacheable! })
332
333
  end
@@ -173,7 +173,7 @@ class ViewModel::ActiveRecord
173
173
  end
174
174
 
175
175
  describe "as belongs_to shared child" do
176
- include ViewModelSpecHelpers::ParentAndSharedChild
176
+ include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
177
177
  include BehavesLikeConstructingAChild
178
178
  it "can clone the model but not the child" do
179
179
  clone_model = Cloner.new.clone(viewmodel)
@@ -1,15 +1,14 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- require "bundler/setup"
4
- Bundler.require
5
-
6
- require_relative "../../../helpers/callback_tracer.rb"
7
- require_relative "../../../helpers/controller_test_helpers.rb"
8
-
9
- require 'byebug'
10
-
11
3
  require "minitest/autorun"
12
4
  require 'minitest/unit'
5
+ require 'minitest/hooks'
6
+
7
+ require "view_model"
8
+ require "view_model/active_record"
9
+
10
+ require_relative "../../../helpers/controller_test_helpers.rb"
11
+ require_relative "../../../helpers/callback_tracer.rb"
13
12
 
14
13
  class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
15
14
  include ARVMTestUtilities
@@ -144,9 +143,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
144
143
  p2_view = ParentView.new(p2)
145
144
  assert(p2.present?, 'p2 created')
146
145
 
147
- context = ParentView.new_serialize_context(include: 'children')
148
- assert_equal({ 'data' => p2_view.to_hash(serialize_context: context) },
149
- parentcontroller.hash_response)
146
+ assert_equal({ 'data' => p2_view.to_hash }, parentcontroller.hash_response)
150
147
 
151
148
  assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
152
149
  end
@@ -210,9 +207,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
210
207
  'detail' => "Couldn't find Parent(s) with id(s)=[9999]",
211
208
  'title' => nil,
212
209
  'code' => "DeserializationError.NotFound",
213
- 'meta' => { 'nodes' => [{ '_type' => "Parent", 'id' => 9999 }]},
214
- 'exception' => nil,
215
- 'causes' => nil }},
210
+ 'meta' => { 'nodes' => [{ '_type' => "Parent", 'id' => 9999 }]}}},
216
211
  parentcontroller.hash_response)
217
212
  end
218
213
 
@@ -234,9 +229,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
234
229
  'meta' => { 'nodes' => [{ '_type' => "Child", 'id' => nil }],
235
230
  'attribute' => 'age',
236
231
  'message' => 'must be less than 42',
237
- 'details' => { 'error' => 'less_than', 'value' => 42, 'count' => 42 }},
238
- 'exception' => nil,
239
- 'causes' => nil }},
232
+ 'details' => { 'error' => 'less_than', 'value' => 42, 'count' => 42 }}}},
240
233
  parentcontroller.hash_response)
241
234
  end
242
235
 
@@ -264,9 +257,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
264
257
  'detail' => "Couldn't find Parent(s) with id(s)=[9999]",
265
258
  'title' => nil,
266
259
  'code' => "DeserializationError.NotFound",
267
- 'meta' => { "nodes" => [{"_type" => "Parent", "id" => 9999 }] },
268
- 'exception' => nil,
269
- 'causes' => nil } },
260
+ 'meta' => { "nodes" => [{"_type" => "Parent", "id" => 9999}]}} },
270
261
  parentcontroller.hash_response)
271
262
  assert_equal(404, parentcontroller.status)
272
263
  end
@@ -337,6 +328,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
337
328
  assert_all_hooks_nested_inside_parent_hook(childcontroller.hook_trace)
338
329
  end
339
330
 
331
+ # FIXME: nested controllers really need to be to other roots; children aren't roots.
340
332
  def test_nested_collection_replace
341
333
  # Parent.children
342
334
  old_children = @parent.children