iknow_view_models 3.2.1 → 3.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/iknow_view_models/version.rb +1 -1
- data/lib/view_model.rb +1 -1
- data/lib/view_model/active_record.rb +5 -4
- data/lib/view_model/active_record/controller.rb +20 -5
- data/lib/view_model/registry.rb +13 -1
- data/test/helpers/controller_test_helpers.rb +11 -4
- data/test/unit/view_model/active_record/controller_test.rb +44 -29
- data/test/unit/view_model/record_test.rb +102 -84
- data/test/unit/view_model/registry_test.rb +38 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 89b29591362703c3bed79c996f0de85f7c8c1f65506bfd70b20f6abcf90f3375
|
4
|
+
data.tar.gz: 81af7a5b3dd3d2c6531019fd65f10d5bcb382a943088eba6e5b16a0eb45d2253
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 185fd079af273bbb14f617f38539b3b72f181e8bdc9af04151705267f6a4d3f21eed99d02401c4010f4d124f0d505b51f9283353bf7da0ae84fa62afbb093ad0
|
7
|
+
data.tar.gz: 3b4dec46423b5bd7090de5c4f1e712e4ce5ef71e969838a52bed724bb42bef6b43c521a32e78c2b0ec948924a6f4311f05607472a4f6061e152413d465b867de
|
data/lib/view_model.rb
CHANGED
@@ -245,7 +245,7 @@ class ViewModel
|
|
245
245
|
|
246
246
|
def schema_hash(schema_versions)
|
247
247
|
version_string = schema_versions.to_a.sort.join(',')
|
248
|
-
Base64.urlsafe_encode64(Digest::MD5.digest(version_string))
|
248
|
+
Base64.urlsafe_encode64(Digest::MD5.digest(version_string), padding: false)
|
249
249
|
end
|
250
250
|
|
251
251
|
def preload_for_serialization(viewmodels, serialize_context: new_serialize_context, include_referenced: true, lock: nil)
|
@@ -224,7 +224,7 @@ class ViewModel::ActiveRecord < ViewModel::Record
|
|
224
224
|
DeepPreloader::Spec.new(association_specs)
|
225
225
|
end
|
226
226
|
|
227
|
-
def dependent_viewmodels(seen = Set.new, include_referenced: true)
|
227
|
+
def dependent_viewmodels(seen = Set.new, include_referenced: true, include_external: true)
|
228
228
|
return if seen.include?(self)
|
229
229
|
|
230
230
|
seen << self
|
@@ -232,19 +232,20 @@ class ViewModel::ActiveRecord < ViewModel::Record
|
|
232
232
|
_members.each_value do |data|
|
233
233
|
next unless data.is_a?(AssociationData)
|
234
234
|
next unless include_referenced || !data.referenced?
|
235
|
+
next unless include_external || !data.external?
|
235
236
|
|
236
237
|
data.viewmodel_classes.each do |vm|
|
237
|
-
vm.dependent_viewmodels(seen, include_referenced: include_referenced)
|
238
|
+
vm.dependent_viewmodels(seen, include_referenced: include_referenced, include_external: include_external)
|
238
239
|
end
|
239
240
|
end
|
240
241
|
|
241
242
|
seen
|
242
243
|
end
|
243
244
|
|
244
|
-
def deep_schema_version(include_referenced: true)
|
245
|
+
def deep_schema_version(include_referenced: true, include_external: true)
|
245
246
|
(@deep_schema_version ||= {})[include_referenced] ||=
|
246
247
|
begin
|
247
|
-
dependent_viewmodels(include_referenced: include_referenced).each_with_object({}) do |view, h|
|
248
|
+
dependent_viewmodels(include_referenced: include_referenced, include_external: include_external).each_with_object({}) do |view, h|
|
248
249
|
h[view.view_name] = view.schema_version
|
249
250
|
end.freeze
|
250
251
|
end
|
@@ -17,6 +17,8 @@ module ViewModel::ActiveRecord::Controller
|
|
17
17
|
include ViewModel::ActiveRecord::CollectionNestedController
|
18
18
|
include ViewModel::ActiveRecord::SingularNestedController
|
19
19
|
|
20
|
+
MIGRATION_VERSION_HEADER = 'X-ViewModel-Versions'
|
21
|
+
|
20
22
|
def show(scope: nil, viewmodel_class: self.viewmodel_class, serialize_context: new_serialize_context(viewmodel_class: viewmodel_class))
|
21
23
|
view = nil
|
22
24
|
pre_rendered = viewmodel_class.transaction do
|
@@ -96,11 +98,24 @@ module ViewModel::ActiveRecord::Controller
|
|
96
98
|
def migration_versions
|
97
99
|
@migration_versions ||=
|
98
100
|
begin
|
99
|
-
|
100
|
-
:versions
|
101
|
-
|
102
|
-
|
103
|
-
|
101
|
+
version_spec =
|
102
|
+
if params.include?(:versions)
|
103
|
+
params[:versions]
|
104
|
+
elsif request.headers.include?(MIGRATION_VERSION_HEADER)
|
105
|
+
begin
|
106
|
+
JSON.parse(request.headers[MIGRATION_VERSION_HEADER])
|
107
|
+
rescue JSON::ParserError
|
108
|
+
raise ViewModel::Error.new(status: 400, detail: "Invalid JSON in #{MIGRATION_VERSION_HEADER}")
|
109
|
+
end
|
110
|
+
else
|
111
|
+
{}
|
112
|
+
end
|
113
|
+
|
114
|
+
versions =
|
115
|
+
IknowParams::Parser.parse_value(
|
116
|
+
version_spec,
|
117
|
+
with: IknowParams::Serializer::HashOf.new(
|
118
|
+
IknowParams::Serializer::String, IknowParams::Serializer::Integer))
|
104
119
|
|
105
120
|
migration_versions = {}
|
106
121
|
|
data/lib/view_model/registry.rb
CHANGED
@@ -6,7 +6,8 @@ class ViewModel::Registry
|
|
6
6
|
DEFERRED_NAME = Object.new
|
7
7
|
|
8
8
|
class << self
|
9
|
-
delegate :for_view_name, :register, :default_view_name, :infer_model_class_name,
|
9
|
+
delegate :for_view_name, :register, :default_view_name, :infer_model_class_name,
|
10
|
+
:clear_removed_classes!, :all, :roots,
|
10
11
|
to: :instance
|
11
12
|
end
|
12
13
|
|
@@ -33,6 +34,17 @@ class ViewModel::Registry
|
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
37
|
+
def all
|
38
|
+
@lock.synchronize do
|
39
|
+
resolve_deferred_classes
|
40
|
+
@viewmodel_classes_by_name.values
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def roots
|
45
|
+
all.select { |c| c.root? }
|
46
|
+
end
|
47
|
+
|
36
48
|
def register(viewmodel, as: DEFERRED_NAME)
|
37
49
|
@lock.synchronize do
|
38
50
|
@deferred_viewmodel_classes << [viewmodel, as]
|
@@ -7,6 +7,8 @@ require 'view_model/active_record/controller'
|
|
7
7
|
require_relative '../helpers/arvm_test_utilities'
|
8
8
|
require_relative '../helpers/arvm_test_models'
|
9
9
|
|
10
|
+
require 'action_controller'
|
11
|
+
|
10
12
|
require 'acts_as_manual_list'
|
11
13
|
|
12
14
|
# models for ARVM controller test
|
@@ -145,11 +147,11 @@ end
|
|
145
147
|
|
146
148
|
## Dummy Rails Controllers
|
147
149
|
class DummyController
|
148
|
-
attr_reader :params, :status
|
150
|
+
attr_reader :params, :headers, :status
|
149
151
|
|
150
|
-
def initialize(
|
151
|
-
|
152
|
-
@
|
152
|
+
def initialize(headers: {}, params: {})
|
153
|
+
@params = ActionController::Parameters.new(params)
|
154
|
+
@headers = ActionDispatch::Http::Headers.from_hash({}).merge!(headers)
|
153
155
|
@status = 200
|
154
156
|
end
|
155
157
|
|
@@ -192,6 +194,11 @@ class DummyController
|
|
192
194
|
JSON.parse(json_response)
|
193
195
|
end
|
194
196
|
|
197
|
+
# for request.params and request.headers
|
198
|
+
def request
|
199
|
+
self
|
200
|
+
end
|
201
|
+
|
195
202
|
class << self
|
196
203
|
def inherited(subclass)
|
197
204
|
subclass.initialize_rescue_blocks
|
@@ -98,7 +98,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def test_show
|
101
|
-
parentcontroller = ParentController.new(id: @parent.id)
|
101
|
+
parentcontroller = ParentController.new(params: { id: @parent.id })
|
102
102
|
parentcontroller.invoke(:show)
|
103
103
|
|
104
104
|
assert_equal({ 'data' => @parent_view.to_hash },
|
@@ -110,7 +110,10 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def test_migrated_show
|
113
|
-
parentcontroller = ParentController.new(
|
113
|
+
parentcontroller = ParentController.new(
|
114
|
+
params: { id: @parent.id },
|
115
|
+
headers: { 'X-ViewModel-Versions' => { ParentView.view_name => 1 }.to_json })
|
116
|
+
|
114
117
|
parentcontroller.invoke(:show)
|
115
118
|
|
116
119
|
expected_view = @parent_view.to_hash
|
@@ -127,6 +130,18 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
127
130
|
assert_all_hooks_nested_inside_parent_hook(parentcontroller.hook_trace)
|
128
131
|
end
|
129
132
|
|
133
|
+
def test_invalid_migration_header
|
134
|
+
parentcontroller = ParentController.new(
|
135
|
+
params: { id: @parent.id },
|
136
|
+
headers: { 'X-ViewModel-Versions' => 'not a json' })
|
137
|
+
|
138
|
+
parentcontroller.invoke(:show)
|
139
|
+
assert_equal(400, parentcontroller.status)
|
140
|
+
assert_match(/Invalid JSON/i,
|
141
|
+
parentcontroller.hash_response['error']['detail'],
|
142
|
+
'json error propagated')
|
143
|
+
end
|
144
|
+
|
130
145
|
def test_index
|
131
146
|
p2 = Parent.create(name: 'p2')
|
132
147
|
p2_view = ParentView.new(p2)
|
@@ -152,7 +167,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
152
167
|
{ '_type' => 'Child', 'name' => 'c2' },],
|
153
168
|
}
|
154
169
|
|
155
|
-
parentcontroller = ParentController.new(data: data)
|
170
|
+
parentcontroller = ParentController.new(params: { data: data })
|
156
171
|
parentcontroller.invoke(:create)
|
157
172
|
|
158
173
|
assert_equal(200, parentcontroller.status)
|
@@ -173,7 +188,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
173
188
|
'old_name' => 'p2',
|
174
189
|
}
|
175
190
|
|
176
|
-
parentcontroller = ParentController.new(data: data, versions: { ParentView.view_name => 1 })
|
191
|
+
parentcontroller = ParentController.new(params: { data: data, versions: { ParentView.view_name => 1 } })
|
177
192
|
parentcontroller.invoke(:create)
|
178
193
|
|
179
194
|
assert_equal(200, parentcontroller.status)
|
@@ -183,14 +198,14 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
183
198
|
end
|
184
199
|
|
185
200
|
def test_create_empty
|
186
|
-
parentcontroller = ParentController.new(data: [])
|
201
|
+
parentcontroller = ParentController.new(params: { data: [] })
|
187
202
|
parentcontroller.invoke(:create)
|
188
203
|
|
189
204
|
assert_equal(400, parentcontroller.status)
|
190
205
|
end
|
191
206
|
|
192
207
|
def test_create_invalid
|
193
|
-
parentcontroller = ParentController.new(data: 42)
|
208
|
+
parentcontroller = ParentController.new(params: { data: 42 })
|
194
209
|
parentcontroller.invoke(:create)
|
195
210
|
|
196
211
|
assert_equal(400, parentcontroller.status)
|
@@ -201,7 +216,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
201
216
|
'_type' => 'Parent',
|
202
217
|
'name' => 'new' }
|
203
218
|
|
204
|
-
parentcontroller = ParentController.new(id: @parent.id, data: data)
|
219
|
+
parentcontroller = ParentController.new(params: { id: @parent.id, data: data })
|
205
220
|
parentcontroller.invoke(:create)
|
206
221
|
|
207
222
|
assert_equal(200, parentcontroller.status)
|
@@ -216,7 +231,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
216
231
|
end
|
217
232
|
|
218
233
|
def test_destroy
|
219
|
-
parentcontroller = ParentController.new(id: @parent.id)
|
234
|
+
parentcontroller = ParentController.new(params: { id: @parent.id })
|
220
235
|
parentcontroller.invoke(:destroy)
|
221
236
|
|
222
237
|
assert_equal(200, parentcontroller.status)
|
@@ -230,7 +245,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
230
245
|
end
|
231
246
|
|
232
247
|
def test_show_missing
|
233
|
-
parentcontroller = ParentController.new(id: 9999)
|
248
|
+
parentcontroller = ParentController.new(params: { id: 9999 })
|
234
249
|
parentcontroller.invoke(:show)
|
235
250
|
|
236
251
|
assert_equal(404, parentcontroller.status)
|
@@ -252,7 +267,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
252
267
|
'children' => [{ '_type' => 'Child',
|
253
268
|
'age' => 42 }] }
|
254
269
|
|
255
|
-
parentcontroller = ParentController.new(data: data)
|
270
|
+
parentcontroller = ParentController.new(params: { data: data })
|
256
271
|
parentcontroller.invoke(:create)
|
257
272
|
|
258
273
|
assert_equal({ 'error' => {
|
@@ -275,7 +290,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
275
290
|
data = { '_type' => 'Parent',
|
276
291
|
'children' => [{ '_type' => 'Child',
|
277
292
|
'age' => 1 }] }
|
278
|
-
parentcontroller = ParentController.new(data: data)
|
293
|
+
parentcontroller = ParentController.new(params: { data: data })
|
279
294
|
parentcontroller.invoke(:create)
|
280
295
|
|
281
296
|
assert_equal(400, parentcontroller.status)
|
@@ -285,7 +300,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
285
300
|
end
|
286
301
|
|
287
302
|
def test_destroy_missing
|
288
|
-
parentcontroller = ParentController.new(id: 9999)
|
303
|
+
parentcontroller = ParentController.new(params: { id: 9999 })
|
289
304
|
parentcontroller.invoke(:destroy)
|
290
305
|
|
291
306
|
assert_equal({ 'error' => {
|
@@ -307,7 +322,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
307
322
|
def test_nested_collection_index_associated
|
308
323
|
_distractor = Parent.create(name: 'p2', children: [Child.new(name: 'c3', position: 1)])
|
309
324
|
|
310
|
-
childcontroller = ChildController.new(parent_id: @parent.id)
|
325
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id })
|
311
326
|
childcontroller.invoke(:index_associated)
|
312
327
|
|
313
328
|
assert_equal(200, childcontroller.status)
|
@@ -334,7 +349,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
334
349
|
|
335
350
|
def test_nested_collection_append_one
|
336
351
|
data = { '_type' => 'Child', 'name' => 'c3' }
|
337
|
-
childcontroller = ChildController.new(parent_id: @parent.id, data: data)
|
352
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
|
338
353
|
|
339
354
|
childcontroller.invoke(:append)
|
340
355
|
|
@@ -353,7 +368,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
353
368
|
data = [{ '_type' => 'Child', 'name' => 'c3' },
|
354
369
|
{ '_type' => 'Child', 'name' => 'c4' },]
|
355
370
|
|
356
|
-
childcontroller = ChildController.new(parent_id: @parent.id, data: data)
|
371
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
|
357
372
|
childcontroller.invoke(:append)
|
358
373
|
|
359
374
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
@@ -376,7 +391,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
376
391
|
data = [{ '_type' => 'Child', 'name' => 'newc1' },
|
377
392
|
{ '_type' => 'Child', 'name' => 'newc2' },]
|
378
393
|
|
379
|
-
childcontroller = ChildController.new(parent_id: @parent.id, data: data)
|
394
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
|
380
395
|
childcontroller.invoke(:replace)
|
381
396
|
|
382
397
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
@@ -391,7 +406,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
391
406
|
|
392
407
|
def test_nested_collection_replace_bad_data
|
393
408
|
data = [{ 'name' => 'nc' }]
|
394
|
-
childcontroller = ChildController.new(parent_id: @parent.id, data: data)
|
409
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, data: data })
|
395
410
|
|
396
411
|
childcontroller.invoke(:replace)
|
397
412
|
|
@@ -402,7 +417,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
402
417
|
|
403
418
|
def test_nested_collection_disassociate_one
|
404
419
|
old_child = @parent.children.first
|
405
|
-
childcontroller = ChildController.new(parent_id: @parent.id, id: old_child.id)
|
420
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id, id: old_child.id })
|
406
421
|
childcontroller.invoke(:disassociate)
|
407
422
|
|
408
423
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
@@ -418,7 +433,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
418
433
|
def test_nested_collection_disassociate_many
|
419
434
|
old_children = @parent.children
|
420
435
|
|
421
|
-
childcontroller = ChildController.new(parent_id: @parent.id)
|
436
|
+
childcontroller = ChildController.new(params: { parent_id: @parent.id })
|
422
437
|
childcontroller.invoke(:disassociate_all)
|
423
438
|
|
424
439
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
@@ -434,7 +449,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
434
449
|
# direct methods on nested controller
|
435
450
|
def test_nested_collection_destroy
|
436
451
|
old_child = @parent.children.first
|
437
|
-
childcontroller = ChildController.new(id: old_child.id)
|
452
|
+
childcontroller = ChildController.new(params: { id: old_child.id })
|
438
453
|
childcontroller.invoke(:destroy)
|
439
454
|
|
440
455
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
@@ -452,7 +467,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
452
467
|
'_type' => 'Child',
|
453
468
|
'name' => 'new_name' }
|
454
469
|
|
455
|
-
childcontroller = ChildController.new(data: data)
|
470
|
+
childcontroller = ChildController.new(params: { data: data })
|
456
471
|
childcontroller.invoke(:create)
|
457
472
|
|
458
473
|
assert_equal(200, childcontroller.status, childcontroller.hash_response)
|
@@ -467,7 +482,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
467
482
|
def test_nested_collection_show
|
468
483
|
old_child = @parent.children.first
|
469
484
|
|
470
|
-
childcontroller = ChildController.new(id: old_child.id)
|
485
|
+
childcontroller = ChildController.new(params: { id: old_child.id })
|
471
486
|
childcontroller.invoke(:show)
|
472
487
|
|
473
488
|
assert_equal({ 'data' => ChildView.new(old_child).to_hash },
|
@@ -482,7 +497,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
482
497
|
old_label = @parent.label
|
483
498
|
|
484
499
|
data = { '_type' => 'Label', 'text' => 'new label' }
|
485
|
-
labelcontroller = LabelController.new(parent_id: @parent.id, data: data)
|
500
|
+
labelcontroller = LabelController.new(params: { parent_id: @parent.id, data: data })
|
486
501
|
labelcontroller.invoke(:create_associated)
|
487
502
|
|
488
503
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|
@@ -504,7 +519,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
504
519
|
def test_nested_singular_show_from_parent
|
505
520
|
old_label = @parent.label
|
506
521
|
|
507
|
-
labelcontroller = LabelController.new(parent_id: @parent.id)
|
522
|
+
labelcontroller = LabelController.new(params: { parent_id: @parent.id })
|
508
523
|
labelcontroller.invoke(:show_associated)
|
509
524
|
|
510
525
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|
@@ -518,7 +533,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
518
533
|
def test_nested_singular_destroy_from_parent
|
519
534
|
old_label = @parent.label
|
520
535
|
|
521
|
-
labelcontroller = LabelController.new(parent_id: @parent.id)
|
536
|
+
labelcontroller = LabelController.new(params: { parent_id: @parent.id })
|
522
537
|
labelcontroller.invoke(:destroy_associated)
|
523
538
|
|
524
539
|
@parent.reload
|
@@ -536,7 +551,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
536
551
|
old_label = @parent.label
|
537
552
|
|
538
553
|
data = { '_type' => 'Label', 'id' => old_label.id, 'text' => 'new label' }
|
539
|
-
labelcontroller = LabelController.new(parent_id: @parent.id, data: data)
|
554
|
+
labelcontroller = LabelController.new(params: { parent_id: @parent.id, data: data })
|
540
555
|
labelcontroller.invoke(:create_associated)
|
541
556
|
|
542
557
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|
@@ -553,7 +568,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
553
568
|
def test_nested_singular_show_from_id
|
554
569
|
old_label = @parent.label
|
555
570
|
|
556
|
-
labelcontroller = LabelController.new(id: old_label.id)
|
571
|
+
labelcontroller = LabelController.new(params: { id: old_label.id })
|
557
572
|
labelcontroller.invoke(:show)
|
558
573
|
|
559
574
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|
@@ -567,7 +582,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
567
582
|
# foreign key violation. Destroy target instead.
|
568
583
|
old_target = @parent.target
|
569
584
|
|
570
|
-
targetcontroller = TargetController.new(id: old_target.id)
|
585
|
+
targetcontroller = TargetController.new(params: { id: old_target.id })
|
571
586
|
targetcontroller.invoke(:destroy)
|
572
587
|
|
573
588
|
@parent.reload
|
@@ -583,7 +598,7 @@ class ViewModel::ActiveRecord::ControllerTest < ActiveSupport::TestCase
|
|
583
598
|
old_label = @parent.label
|
584
599
|
|
585
600
|
data = { '_type' => 'Label', 'id' => old_label.id, 'text' => 'new label' }
|
586
|
-
labelcontroller = LabelController.new(data: data)
|
601
|
+
labelcontroller = LabelController.new(params: { data: data })
|
587
602
|
labelcontroller.invoke(:create)
|
588
603
|
|
589
604
|
assert_equal(200, labelcontroller.status, labelcontroller.hash_response)
|
@@ -365,122 +365,140 @@ class ViewModel::RecordTest < ActiveSupport::TestCase
|
|
365
365
|
end
|
366
366
|
end
|
367
367
|
|
368
|
-
|
368
|
+
describe 'nesting' do
|
369
|
+
let(:nested_model_class) do
|
370
|
+
klass = Struct.new(:member)
|
371
|
+
Object.const_set(:Nested, klass)
|
372
|
+
klass
|
373
|
+
end
|
369
374
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
+
let(:nested_viewmodel_class) do
|
376
|
+
mc = nested_model_class
|
377
|
+
klass = Class.new(TestViewModel) do
|
378
|
+
self.view_name = 'Nested'
|
379
|
+
self.model_class = mc
|
380
|
+
attribute :member
|
381
|
+
end
|
382
|
+
Object.const_set(:NestedView, klass)
|
383
|
+
klass
|
384
|
+
end
|
375
385
|
|
376
|
-
|
377
|
-
|
378
|
-
|
386
|
+
def teardown
|
387
|
+
Object.send(:remove_const, :Nested)
|
388
|
+
Object.send(:remove_const, :NestedView)
|
389
|
+
ActiveSupport::Dependencies::Reference.clear!
|
390
|
+
super
|
391
|
+
end
|
379
392
|
|
380
|
-
|
393
|
+
describe 'with nested viewmodel' do
|
394
|
+
let(:default_nested_model) { nested_model_class.new('member') }
|
395
|
+
let(:default_nested_view) { view_base.merge('_type' => 'Nested', 'member' => 'member') }
|
381
396
|
|
382
|
-
|
383
|
-
let(:default_model_values) { { nested: default_nested_model } }
|
397
|
+
let(:attributes) { { simple: {}, nested: { using: nested_viewmodel_class } } }
|
384
398
|
|
385
|
-
|
386
|
-
|
387
|
-
access_control: access_control)
|
388
|
-
end
|
399
|
+
let(:default_view_values) { { nested: default_nested_view } }
|
400
|
+
let(:default_model_values) { { nested: default_nested_model } }
|
389
401
|
|
390
|
-
|
391
|
-
|
392
|
-
|
402
|
+
let(:update_context) do
|
403
|
+
TestDeserializeContext.new(targets: [default_model, default_nested_model],
|
404
|
+
access_control: access_control)
|
405
|
+
end
|
393
406
|
|
394
|
-
|
395
|
-
|
407
|
+
include CanSerialize
|
408
|
+
include CanDeserializeToNew
|
409
|
+
include CanDeserializeToExisting
|
396
410
|
|
397
|
-
|
411
|
+
it 'can update the nested value' do
|
412
|
+
new_view = default_view.merge('nested' => default_nested_view.merge('member' => 'changed'))
|
398
413
|
|
399
|
-
|
400
|
-
assert(default_nested_model.equal?(vm.model.nested), 'returned nested model was not the same')
|
414
|
+
vm = viewmodel_class.deserialize_from_view(new_view, deserialize_context: update_context)
|
401
415
|
|
402
|
-
|
416
|
+
assert(default_model.equal?(vm.model), 'returned model was not the same')
|
417
|
+
assert(default_nested_model.equal?(vm.model.nested), 'returned nested model was not the same')
|
403
418
|
|
404
|
-
|
405
|
-
assert_edited(vm.nested, changed_attributes: [:member])
|
406
|
-
end
|
419
|
+
assert_equal('changed', default_model.nested.member)
|
407
420
|
|
408
|
-
|
409
|
-
|
410
|
-
|
421
|
+
assert_unchanged(vm)
|
422
|
+
assert_edited(vm.nested, changed_attributes: [:member])
|
423
|
+
end
|
411
424
|
|
412
|
-
|
413
|
-
|
425
|
+
it 'can replace the nested value' do
|
426
|
+
# The value will be unified if it is different after deserialization
|
427
|
+
new_view = default_view.merge('nested' => default_nested_view.merge('member' => 'changed'))
|
414
428
|
|
415
|
-
|
429
|
+
partial_update_context = TestDeserializeContext.new(targets: [default_model],
|
430
|
+
access_control: access_control)
|
416
431
|
|
417
|
-
|
418
|
-
refute(default_nested_model.equal?(vm.model.nested), 'returned nested model was the same')
|
432
|
+
vm = viewmodel_class.deserialize_from_view(new_view, deserialize_context: partial_update_context)
|
419
433
|
|
420
|
-
|
421
|
-
|
434
|
+
assert(default_model.equal?(vm.model), 'returned model was not the same')
|
435
|
+
refute(default_nested_model.equal?(vm.model.nested), 'returned nested model was the same')
|
436
|
+
|
437
|
+
assert_edited(vm, new: false, changed_attributes: [:nested])
|
438
|
+
assert_edited(vm.nested, new: true, changed_attributes: [:member])
|
439
|
+
end
|
422
440
|
end
|
423
|
-
end
|
424
441
|
|
425
|
-
|
426
|
-
|
427
|
-
|
442
|
+
describe 'with array of nested viewmodel' do
|
443
|
+
let(:default_nested_model_1) { nested_model_class.new('member1') }
|
444
|
+
let(:default_nested_view_1) { view_base.merge('_type' => 'Nested', 'member' => 'member1') }
|
428
445
|
|
429
|
-
|
430
|
-
|
446
|
+
let(:default_nested_model_2) { nested_model_class.new('member2') }
|
447
|
+
let(:default_nested_view_2) { view_base.merge('_type' => 'Nested', 'member' => 'member2') }
|
431
448
|
|
432
|
-
|
449
|
+
let(:attributes) { { simple: {}, nested: { using: nested_viewmodel_class, array: true } } }
|
433
450
|
|
434
|
-
|
435
|
-
|
451
|
+
let(:default_view_values) { { nested: [default_nested_view_1, default_nested_view_2] } }
|
452
|
+
let(:default_model_values) { { nested: [default_nested_model_1, default_nested_model_2] } }
|
436
453
|
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
454
|
+
let(:update_context) {
|
455
|
+
TestDeserializeContext.new(targets: [default_model, default_nested_model_1, default_nested_model_2],
|
456
|
+
access_control: access_control)
|
457
|
+
}
|
441
458
|
|
442
|
-
|
443
|
-
|
444
|
-
|
459
|
+
include CanSerialize
|
460
|
+
include CanDeserializeToNew
|
461
|
+
include CanDeserializeToExisting
|
445
462
|
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
463
|
+
it 'rejects change to attribute' do
|
464
|
+
new_view = default_view.merge('nested' => 'terrible')
|
465
|
+
ex = assert_raises(ViewModel::DeserializationError::InvalidAttributeType) do
|
466
|
+
viewmodel_class.deserialize_from_view(new_view, deserialize_context: update_context)
|
467
|
+
end
|
468
|
+
assert_equal('nested', ex.attribute)
|
469
|
+
assert_equal('Array', ex.expected_type)
|
470
|
+
assert_equal('String', ex.provided_type)
|
450
471
|
end
|
451
|
-
assert_equal('nested', ex.attribute)
|
452
|
-
assert_equal('Array', ex.expected_type)
|
453
|
-
assert_equal('String', ex.provided_type)
|
454
|
-
end
|
455
472
|
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
473
|
+
it 'can edit a nested value' do
|
474
|
+
default_view['nested'][0]['member'] = 'changed'
|
475
|
+
vm = viewmodel_class.deserialize_from_view(default_view, deserialize_context: update_context)
|
476
|
+
assert(default_model.equal?(vm.model), 'returned model was not the same')
|
477
|
+
assert_equal(2, vm.model.nested.size)
|
478
|
+
assert(default_nested_model_1.equal?(vm.model.nested[0]))
|
479
|
+
assert(default_nested_model_2.equal?(vm.model.nested[1]))
|
463
480
|
|
464
|
-
|
465
|
-
|
466
|
-
|
481
|
+
assert_unchanged(vm)
|
482
|
+
assert_edited(vm.nested[0], changed_attributes: [:member])
|
483
|
+
end
|
467
484
|
|
468
|
-
|
469
|
-
|
485
|
+
it 'can append a nested value' do
|
486
|
+
default_view['nested'] << view_base.merge('_type' => 'Nested', 'member' => 'member3')
|
470
487
|
|
471
|
-
|
488
|
+
vm = viewmodel_class.deserialize_from_view(default_view, deserialize_context: update_context)
|
472
489
|
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
490
|
+
assert(default_model.equal?(vm.model), 'returned model was not the same')
|
491
|
+
assert_equal(3, vm.model.nested.size)
|
492
|
+
assert(default_nested_model_1.equal?(vm.model.nested[0]))
|
493
|
+
assert(default_nested_model_2.equal?(vm.model.nested[1]))
|
477
494
|
|
478
|
-
|
479
|
-
|
480
|
-
|
495
|
+
vm.model.nested.each_with_index do |nvm, i|
|
496
|
+
assert_equal("member#{i + 1}", nvm.member)
|
497
|
+
end
|
481
498
|
|
482
|
-
|
483
|
-
|
499
|
+
assert_edited(vm, changed_attributes: [:nested])
|
500
|
+
assert_edited(vm.nested[2], new: true, changed_attributes: [:member])
|
501
|
+
end
|
484
502
|
end
|
485
503
|
end
|
486
504
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
require 'minitest/hooks'
|
6
|
+
|
7
|
+
require_relative '../../helpers/arvm_test_utilities'
|
8
|
+
require_relative '../../helpers/arvm_test_models'
|
9
|
+
require_relative '../../helpers/viewmodel_spec_helpers'
|
10
|
+
|
11
|
+
require 'view_model'
|
12
|
+
require 'view_model/active_record'
|
13
|
+
|
14
|
+
class ViewModel
|
15
|
+
class RegistryTest < ActiveSupport::TestCase
|
16
|
+
using ViewModel::Utils::Collections
|
17
|
+
include ARVMTestUtilities
|
18
|
+
extend Minitest::Spec::DSL
|
19
|
+
include ViewModelSpecHelpers::ParentAndBelongsToChild
|
20
|
+
|
21
|
+
before(:each) do
|
22
|
+
ViewModel::Registry.clear_removed_classes!
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'registers the views' do
|
26
|
+
assert_equal(ViewModel::Registry.for_view_name(view_name), viewmodel_class)
|
27
|
+
assert_equal(ViewModel::Registry.for_view_name(child_view_name), child_viewmodel_class)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'enumerates the views' do
|
31
|
+
assert_contains_exactly([ViewModel::ErrorView, viewmodel_class, child_viewmodel_class], ViewModel::Registry.all)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'enumerates the root views' do
|
35
|
+
assert_contains_exactly([viewmodel_class], ViewModel::Registry.roots)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: iknow_view_models
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iKnow Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -468,6 +468,7 @@ files:
|
|
468
468
|
- test/unit/view_model/controller_test.rb
|
469
469
|
- test/unit/view_model/deserialization_error/unique_violation_test.rb
|
470
470
|
- test/unit/view_model/record_test.rb
|
471
|
+
- test/unit/view_model/registry_test.rb
|
471
472
|
- test/unit/view_model/traversal_context_test.rb
|
472
473
|
- test/unit/view_model_test.rb
|
473
474
|
homepage: https://github.com/iknow/cerego_view_models
|
@@ -527,5 +528,6 @@ test_files:
|
|
527
528
|
- test/unit/view_model/controller_test.rb
|
528
529
|
- test/unit/view_model/deserialization_error/unique_violation_test.rb
|
529
530
|
- test/unit/view_model/record_test.rb
|
531
|
+
- test/unit/view_model/registry_test.rb
|
530
532
|
- test/unit/view_model/traversal_context_test.rb
|
531
533
|
- test/unit/view_model_test.rb
|