iknow_view_models 3.2.0 → 3.2.1
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +13 -0
- data/Appraisals +6 -6
- data/Rakefile +5 -5
- data/gemfiles/rails_5_2.gemfile +5 -5
- data/gemfiles/rails_6_0.gemfile +5 -5
- data/iknow_view_models.gemspec +40 -39
- data/lib/iknow_view_models.rb +9 -7
- data/lib/iknow_view_models/version.rb +1 -1
- data/lib/view_model.rb +17 -14
- data/lib/view_model/access_control.rb +5 -2
- data/lib/view_model/access_control/composed.rb +10 -9
- data/lib/view_model/access_control/open.rb +2 -0
- data/lib/view_model/access_control/read_only.rb +2 -0
- data/lib/view_model/access_control/tree.rb +11 -6
- data/lib/view_model/access_control_error.rb +4 -1
- data/lib/view_model/active_record.rb +12 -11
- data/lib/view_model/active_record/association_data.rb +2 -1
- data/lib/view_model/active_record/association_manipulation.rb +6 -4
- data/lib/view_model/active_record/cache.rb +4 -2
- data/lib/view_model/active_record/collection_nested_controller.rb +3 -3
- data/lib/view_model/active_record/controller_base.rb +4 -1
- data/lib/view_model/active_record/nested_controller_base.rb +1 -0
- data/lib/view_model/active_record/update_context.rb +8 -6
- data/lib/view_model/active_record/update_data.rb +32 -30
- data/lib/view_model/active_record/update_operation.rb +17 -13
- data/lib/view_model/active_record/visitor.rb +0 -1
- data/lib/view_model/after_transaction_runner.rb +0 -1
- data/lib/view_model/callbacks.rb +3 -1
- data/lib/view_model/controller.rb +13 -3
- data/lib/view_model/deserialization_error.rb +15 -12
- data/lib/view_model/error.rb +12 -10
- data/lib/view_model/error_view.rb +3 -1
- data/lib/view_model/migration/no_path_error.rb +1 -0
- data/lib/view_model/migration/one_way_error.rb +1 -0
- data/lib/view_model/migration/unspecified_version_error.rb +1 -0
- data/lib/view_model/record.rb +11 -13
- data/lib/view_model/reference.rb +3 -1
- data/lib/view_model/references.rb +8 -5
- data/lib/view_model/registry.rb +1 -1
- data/lib/view_model/schemas.rb +9 -4
- data/lib/view_model/serialization_error.rb +4 -1
- data/lib/view_model/serialize_context.rb +4 -4
- data/lib/view_model/test_helpers.rb +8 -3
- data/lib/view_model/test_helpers/arvm_builder.rb +19 -14
- data/lib/view_model/traversal_context.rb +2 -1
- data/test/.rubocop.yml +14 -0
- data/test/helpers/arvm_test_models.rb +12 -9
- data/test/helpers/arvm_test_utilities.rb +5 -3
- data/test/helpers/controller_test_helpers.rb +31 -29
- data/test/helpers/match_enumerator.rb +1 -0
- data/test/helpers/query_logging.rb +2 -1
- data/test/helpers/test_access_control.rb +5 -3
- data/test/helpers/viewmodel_spec_helpers.rb +21 -20
- data/test/unit/view_model/access_control_test.rb +144 -144
- data/test/unit/view_model/active_record/alias_test.rb +15 -13
- data/test/unit/view_model/active_record/belongs_to_test.rb +40 -39
- data/test/unit/view_model/active_record/cache_test.rb +27 -26
- data/test/unit/view_model/active_record/cloner_test.rb +67 -63
- data/test/unit/view_model/active_record/controller_test.rb +37 -38
- data/test/unit/view_model/active_record/counter_test.rb +10 -9
- data/test/unit/view_model/active_record/customization_test.rb +59 -58
- data/test/unit/view_model/active_record/has_many_test.rb +112 -111
- data/test/unit/view_model/active_record/has_many_through_poly_test.rb +15 -14
- data/test/unit/view_model/active_record/has_many_through_test.rb +33 -38
- data/test/unit/view_model/active_record/has_one_test.rb +37 -36
- data/test/unit/view_model/active_record/migration_test.rb +13 -13
- data/test/unit/view_model/active_record/namespacing_test.rb +19 -17
- data/test/unit/view_model/active_record/poly_test.rb +44 -45
- data/test/unit/view_model/active_record/shared_test.rb +30 -28
- data/test/unit/view_model/active_record/version_test.rb +9 -7
- data/test/unit/view_model/active_record_test.rb +72 -72
- data/test/unit/view_model/callbacks_test.rb +19 -15
- data/test/unit/view_model/controller_test.rb +4 -2
- data/test/unit/view_model/record_test.rb +92 -97
- data/test/unit/view_model/traversal_context_test.rb +4 -5
- data/test/unit/view_model_test.rb +18 -16
- metadata +7 -5
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
require_relative "../../../helpers/arvm_test_models.rb"
|
3
|
-
require_relative "../../../helpers/viewmodel_spec_helpers.rb"
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
3
|
+
require_relative '../../../helpers/arvm_test_utilities'
|
4
|
+
require_relative '../../../helpers/arvm_test_models'
|
5
|
+
require_relative '../../../helpers/viewmodel_spec_helpers'
|
6
6
|
|
7
|
-
require
|
7
|
+
require 'minitest/autorun'
|
8
|
+
|
9
|
+
require 'view_model/active_record'
|
8
10
|
|
9
11
|
class ViewModel::ActiveRecord::Alias < ActiveSupport::TestCase
|
10
12
|
include ARVMTestUtilities
|
@@ -14,18 +16,18 @@ class ViewModel::ActiveRecord::Alias < ActiveSupport::TestCase
|
|
14
16
|
|
15
17
|
def child_attributes
|
16
18
|
super.merge(
|
17
|
-
viewmodel: ->(
|
18
|
-
add_view_alias
|
19
|
-
add_view_alias
|
20
|
-
end
|
19
|
+
viewmodel: ->(_v) do
|
20
|
+
add_view_alias 'ChildA'
|
21
|
+
add_view_alias 'ChildB'
|
22
|
+
end,
|
21
23
|
)
|
22
24
|
end
|
23
25
|
|
24
|
-
it
|
25
|
-
%w
|
26
|
+
it 'permits association types to be aliased' do
|
27
|
+
%w[Child ChildA ChildB].each do |view_alias|
|
26
28
|
view = {
|
27
|
-
|
28
|
-
|
29
|
+
'_type' => viewmodel_class.view_name,
|
30
|
+
'child' => { '_type' => view_alias },
|
29
31
|
}
|
30
32
|
|
31
33
|
parent = viewmodel_class.deserialize_from_view(view).model
|
@@ -1,10 +1,12 @@
|
|
1
|
-
|
2
|
-
require_relative "../../../helpers/arvm_test_models.rb"
|
3
|
-
require_relative '../../../helpers/viewmodel_spec_helpers.rb'
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
3
|
+
require_relative '../../../helpers/arvm_test_utilities'
|
4
|
+
require_relative '../../../helpers/arvm_test_models'
|
5
|
+
require_relative '../../../helpers/viewmodel_spec_helpers'
|
6
6
|
|
7
|
-
require
|
7
|
+
require 'minitest/autorun'
|
8
|
+
|
9
|
+
require 'view_model/active_record'
|
8
10
|
|
9
11
|
class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
10
12
|
include ARVMTestUtilities
|
@@ -14,13 +16,13 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
14
16
|
def setup
|
15
17
|
super
|
16
18
|
|
17
|
-
# TODO make a `has_list?` that allows a parent to set all children as an array
|
18
|
-
@model1 = model_class.new(name:
|
19
|
-
child: child_model_class.new(name:
|
19
|
+
# TODO: make a `has_list?` that allows a parent to set all children as an array
|
20
|
+
@model1 = model_class.new(name: 'p1',
|
21
|
+
child: child_model_class.new(name: 'p1l'))
|
20
22
|
@model1.save!
|
21
23
|
|
22
|
-
@model2 = model_class.new(name:
|
23
|
-
child: child_model_class.new(name:
|
24
|
+
@model2 = model_class.new(name: 'p2',
|
25
|
+
child: child_model_class.new(name: 'p2l'))
|
24
26
|
|
25
27
|
@model2.save!
|
26
28
|
|
@@ -30,14 +32,14 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
30
32
|
def test_serialize_view
|
31
33
|
view, _refs = serialize_with_references(ModelView.new(@model1))
|
32
34
|
|
33
|
-
assert_equal({
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
35
|
+
assert_equal({ '_type' => 'Model',
|
36
|
+
'_version' => 1,
|
37
|
+
'id' => @model1.id,
|
38
|
+
'name' => @model1.name,
|
39
|
+
'child' => { '_type' => 'Child',
|
40
|
+
'_version' => 1,
|
41
|
+
'id' => @model1.child.id,
|
42
|
+
'name' => @model1.child.name },
|
41
43
|
},
|
42
44
|
view)
|
43
45
|
end
|
@@ -53,9 +55,9 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
53
55
|
|
54
56
|
def test_create_from_view
|
55
57
|
view = {
|
56
|
-
|
57
|
-
|
58
|
-
|
58
|
+
'_type' => 'Model',
|
59
|
+
'name' => 'p',
|
60
|
+
'child' => { '_type' => 'Child', 'name' => 'l' },
|
59
61
|
}
|
60
62
|
|
61
63
|
pv = ModelView.deserialize_from_view(view)
|
@@ -64,10 +66,10 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
64
66
|
assert(!p.changed?)
|
65
67
|
assert(!p.new_record?)
|
66
68
|
|
67
|
-
assert_equal(
|
69
|
+
assert_equal('p', p.name)
|
68
70
|
|
69
71
|
assert(p.child.present?)
|
70
|
-
assert_equal(
|
72
|
+
assert_equal('l', p.child.name)
|
71
73
|
end
|
72
74
|
|
73
75
|
def test_create_belongs_to_nil
|
@@ -86,7 +88,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
86
88
|
def test_belongs_to_create
|
87
89
|
@model1.update(child: nil)
|
88
90
|
|
89
|
-
alter_by_view!(ModelView, @model1) do |view,
|
91
|
+
alter_by_view!(ModelView, @model1) do |view, _refs|
|
90
92
|
view['child'] = { '_type' => 'Child', 'name' => 'cheese' }
|
91
93
|
end
|
92
94
|
|
@@ -96,7 +98,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
96
98
|
def test_belongs_to_replace
|
97
99
|
old_child = @model1.child
|
98
100
|
|
99
|
-
alter_by_view!(ModelView, @model1) do |view,
|
101
|
+
alter_by_view!(ModelView, @model1) do |view, _refs|
|
100
102
|
view['child'] = { '_type' => 'Child', 'name' => 'cheese' }
|
101
103
|
end
|
102
104
|
|
@@ -108,7 +110,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
108
110
|
old_p1_child = @model1.child
|
109
111
|
old_p2_child = @model2.child
|
110
112
|
|
111
|
-
set_by_view!(ModelView, [@model1, @model2]) do |(p1, p2),
|
113
|
+
set_by_view!(ModelView, [@model1, @model2]) do |(p1, p2), _refs|
|
112
114
|
p1['child'] = nil
|
113
115
|
p2['child'] = update_hash_for(ChildView, old_p1_child)
|
114
116
|
end
|
@@ -122,7 +124,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
122
124
|
old_p1_child = @model1.child
|
123
125
|
old_p2_child = @model2.child
|
124
126
|
|
125
|
-
alter_by_view!(ModelView, [@model1, @model2]) do |(p1, p2),
|
127
|
+
alter_by_view!(ModelView, [@model1, @model2]) do |(p1, p2), _refs|
|
126
128
|
p1['child'] = update_hash_for(ChildView, old_p2_child)
|
127
129
|
p2['child'] = update_hash_for(ChildView, old_p1_child)
|
128
130
|
end
|
@@ -136,22 +138,22 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
136
138
|
d_context = ModelView.new_deserialize_context
|
137
139
|
|
138
140
|
target_child = Child.create
|
139
|
-
from_model
|
140
|
-
to_model
|
141
|
+
from_model = Model.create(name: 'from', child: target_child)
|
142
|
+
to_model = Model.create(name: 'p3')
|
141
143
|
|
142
144
|
alter_by_view!(
|
143
145
|
ModelView, [from_model, to_model],
|
144
146
|
deserialize_context: d_context
|
145
|
-
) do |(from, to),
|
147
|
+
) do |(from, to), _refs|
|
146
148
|
from['child'] = nil
|
147
149
|
to['child'] = update_hash_for(ChildView, target_child)
|
148
150
|
end
|
149
151
|
|
150
152
|
assert_equal(target_child, to_model.child, 'target child moved')
|
151
153
|
assert_equal([ViewModel::Reference.new(ModelView, from_model.id),
|
152
|
-
ViewModel::Reference.new(ModelView, to_model.id)],
|
154
|
+
ViewModel::Reference.new(ModelView, to_model.id),],
|
153
155
|
d_context.valid_edit_refs,
|
154
|
-
|
156
|
+
'only models are checked for change; child was not')
|
155
157
|
end
|
156
158
|
|
157
159
|
def test_implicit_release_invalid_belongs_to
|
@@ -174,11 +176,11 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
174
176
|
t.integer :deleted_child_id
|
175
177
|
t.integer :ignored_child_id
|
176
178
|
end,
|
177
|
-
model: ->(
|
179
|
+
model: ->(_m) do
|
178
180
|
belongs_to :deleted_child, class_name: Child.name, dependent: :delete
|
179
181
|
belongs_to :ignored_child, class_name: Child.name
|
180
182
|
end,
|
181
|
-
viewmodel: ->(
|
183
|
+
viewmodel: ->(_v) do
|
182
184
|
associations :deleted_child, :ignored_child
|
183
185
|
end)
|
184
186
|
end
|
@@ -198,7 +200,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
198
200
|
end
|
199
201
|
|
200
202
|
def test_no_gc_dependent_ignore
|
201
|
-
model = model_class.create(ignored_child: Child.new(name:
|
203
|
+
model = model_class.create(ignored_child: Child.new(name: 'one'))
|
202
204
|
old_child = model.ignored_child
|
203
205
|
|
204
206
|
alter_by_view!(ModelView, model) do |ov, _refs|
|
@@ -232,7 +234,7 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
232
234
|
end
|
233
235
|
|
234
236
|
def test_renamed_roundtrip
|
235
|
-
alter_by_view!(ModelView, @model) do |view,
|
237
|
+
alter_by_view!(ModelView, @model) do |view, _refs|
|
236
238
|
assert_equal({ 'id' => @model.child.id,
|
237
239
|
'_type' => 'Child',
|
238
240
|
'_version' => 1,
|
@@ -284,7 +286,6 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
284
286
|
end
|
285
287
|
end
|
286
288
|
|
287
|
-
|
288
289
|
# Do we support replacing a node in the tree and remodeling its children
|
289
290
|
# back to it? In theory we want to, but currently we don't: the child node
|
290
291
|
# is unresolvable.
|
@@ -299,8 +300,8 @@ class ViewModel::ActiveRecord::BelongsToTest < ActiveSupport::TestCase
|
|
299
300
|
def test_move
|
300
301
|
model = Aye.create(bee: Bee.new(cee: Cee.new))
|
301
302
|
assert_raises(ViewModel::DeserializationError::ParentNotFound) do
|
302
|
-
alter_by_view!(AyeView, model) do |view,
|
303
|
-
view['bee'].delete(
|
303
|
+
alter_by_view!(AyeView, model) do |view, _refs|
|
304
|
+
view['bee'].delete('id')
|
304
305
|
end
|
305
306
|
end
|
306
307
|
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
require 'minitest/hooks'
|
6
6
|
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
7
|
+
require_relative '../../../helpers/arvm_test_models'
|
8
|
+
require_relative '../../../helpers/arvm_test_utilities'
|
9
|
+
require_relative '../../../helpers/viewmodel_spec_helpers'
|
10
10
|
|
11
|
-
require
|
12
|
-
require
|
11
|
+
require 'view_model'
|
12
|
+
require 'view_model/active_record'
|
13
13
|
|
14
14
|
# IknowCache uses Rails.cache: create a dummy cache.
|
15
15
|
|
@@ -91,8 +91,8 @@ class ViewModel::ActiveRecord
|
|
91
91
|
end
|
92
92
|
|
93
93
|
included do
|
94
|
-
let(:shared) { shared_model_class.create!(name:
|
95
|
-
let(:root) { model_class.create!(name:
|
94
|
+
let(:shared) { shared_model_class.create!(name: 'shared1') }
|
95
|
+
let(:root) { model_class.create!(name: 'root1', child: Child.new(name: 'owned1'), shared: shared) }
|
96
96
|
let(:root_view) { viewmodel_class.new(root) }
|
97
97
|
end
|
98
98
|
end
|
@@ -183,13 +183,14 @@ class ViewModel::ActiveRecord
|
|
183
183
|
|
184
184
|
# The cached reference must correspond to the returned data.
|
185
185
|
parsed_data = JSON.parse(ref_data)
|
186
|
-
value(parsed_data[
|
187
|
-
value(parsed_data[
|
186
|
+
value(parsed_data['id']).must_equal(id)
|
187
|
+
value(parsed_data['_type']).must_equal(view_name)
|
188
188
|
|
189
189
|
# When the cached reference is to independently cached data
|
190
190
|
# (SharedView in this test), make sure that data is correctly
|
191
191
|
# cached.
|
192
|
-
next unless view_name ==
|
192
|
+
next unless view_name == 'Shared'
|
193
|
+
|
193
194
|
value(id).must_equal(shared.id)
|
194
195
|
cached_shared = read_cache(shared_viewmodel_class, id)
|
195
196
|
value(cached_shared).must_be(:present?)
|
@@ -224,8 +225,8 @@ class ViewModel::ActiveRecord
|
|
224
225
|
end
|
225
226
|
|
226
227
|
def change_in_database
|
227
|
-
root.update_attribute(:name,
|
228
|
-
shared.update_attribute(:name,
|
228
|
+
root.update_attribute(:name, 'CHANGEDROOT')
|
229
|
+
shared.update_attribute(:name, 'CHANGEDSHARED')
|
229
230
|
end
|
230
231
|
|
231
232
|
it 'resolves from the cache' do
|
@@ -243,7 +244,7 @@ class ViewModel::ActiveRecord
|
|
243
244
|
viewmodel_class.viewmodel_cache.clear
|
244
245
|
|
245
246
|
cache_data, cache_refs = serialize_with_cache
|
246
|
-
value(cache_data[0][
|
247
|
+
value(cache_data[0]['name']).must_equal('CHANGEDROOT') # Root view invalidated
|
247
248
|
value(cache_refs).must_equal(before_refs) # Shared view not invalidated
|
248
249
|
end
|
249
250
|
|
@@ -301,7 +302,7 @@ class ViewModel::ActiveRecord
|
|
301
302
|
viewmodel_class.viewmodel_cache.delete(root.id)
|
302
303
|
|
303
304
|
cache_data, cache_refs = serialize_with_cache
|
304
|
-
value(cache_data[0][
|
305
|
+
value(cache_data[0]['name']).must_equal('CHANGEDROOT')
|
305
306
|
value(cache_refs).must_equal(before_refs)
|
306
307
|
end
|
307
308
|
|
@@ -311,8 +312,8 @@ class ViewModel::ActiveRecord
|
|
311
312
|
|
312
313
|
# Shared view invalidated, but root view not
|
313
314
|
cache_data, cache_hrefs = serialize_with_cache
|
314
|
-
value(cache_data[0][
|
315
|
-
value(cache_hrefs.values[0][
|
315
|
+
value(cache_data[0]['name']).must_equal('root1')
|
316
|
+
value(cache_hrefs.values[0]['name']).must_equal('CHANGEDSHARED')
|
316
317
|
end
|
317
318
|
|
318
319
|
it 'can clear a cache via its external cache group' do
|
@@ -321,12 +322,12 @@ class ViewModel::ActiveRecord
|
|
321
322
|
|
322
323
|
# Shared view invalidated, but root view not
|
323
324
|
cache_data, cache_hrefs = serialize_with_cache
|
324
|
-
value(cache_data[0][
|
325
|
-
value(cache_hrefs.values[0][
|
325
|
+
value(cache_data[0]['name']).must_equal('root1')
|
326
|
+
value(cache_hrefs.values[0]['name']).must_equal('CHANGEDSHARED')
|
326
327
|
end
|
327
328
|
|
328
329
|
describe 'and a record not in the cache' do
|
329
|
-
let(:root2) { model_class.create!(name:
|
330
|
+
let(:root2) { model_class.create!(name: 'root2', child: Child.new(name: 'owned2'), shared: shared) }
|
330
331
|
|
331
332
|
def serialize_from_database
|
332
333
|
views = model_class.find(root.id, root2.id).map { |r| viewmodel_class.new(r) }
|
@@ -354,21 +355,21 @@ class ViewModel::ActiveRecord
|
|
354
355
|
change_in_database
|
355
356
|
|
356
357
|
cache_data, cache_refs = serialize_with_cache
|
357
|
-
value(cache_data[0][
|
358
|
-
value(cache_data[1][
|
358
|
+
value(cache_data[0]['name']).must_equal('root1')
|
359
|
+
value(cache_data[1]['name']).must_equal('root2')
|
359
360
|
value(cache_refs).must_equal(refs)
|
360
361
|
end
|
361
362
|
end
|
362
363
|
end
|
363
364
|
end
|
364
365
|
|
365
|
-
describe
|
366
|
+
describe 'with a non-cacheable shared child' do
|
366
367
|
include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
|
367
368
|
def model_attributes
|
368
369
|
super.merge(viewmodel: ->(_) { cacheable! })
|
369
370
|
end
|
370
371
|
|
371
|
-
let(:root) { model_class.create!(name:
|
372
|
+
let(:root) { model_class.create!(name: 'root1', child: Child.new(name: 'owned1')) }
|
372
373
|
let(:root_view) { viewmodel_class.new(root) }
|
373
374
|
|
374
375
|
include BehavesLikeACache
|
@@ -1,14 +1,16 @@
|
|
1
|
-
|
2
|
-
require "minitest/unit"
|
3
|
-
require "minitest/hooks"
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'minitest/unit'
|
5
|
+
require 'minitest/hooks'
|
6
|
+
|
7
|
+
require_relative '../../../helpers/arvm_test_models'
|
8
|
+
require_relative '../../../helpers/viewmodel_spec_helpers'
|
7
9
|
|
8
10
|
# MiniTest::Spec.register_spec_type(/./, Minitest::HooksSpec)
|
9
11
|
|
10
|
-
require
|
11
|
-
require
|
12
|
+
require 'view_model'
|
13
|
+
require 'view_model/active_record'
|
12
14
|
|
13
15
|
class ViewModel::ActiveRecord
|
14
16
|
class ClonerTest < ActiveSupport::TestCase
|
@@ -18,7 +20,7 @@ class ViewModel::ActiveRecord
|
|
18
20
|
let(:viewmodel) { create_viewmodel! }
|
19
21
|
let(:model) { viewmodel.model }
|
20
22
|
|
21
|
-
describe
|
23
|
+
describe 'with single model' do
|
22
24
|
include ViewModelSpecHelpers::Single
|
23
25
|
|
24
26
|
def model_attributes
|
@@ -26,15 +28,15 @@ class ViewModel::ActiveRecord
|
|
26
28
|
end
|
27
29
|
|
28
30
|
def new_model
|
29
|
-
model_class.new(name:
|
31
|
+
model_class.new(name: 'a', nonview: 'b')
|
30
32
|
end
|
31
33
|
|
32
|
-
it
|
34
|
+
it 'persists the test setup' do
|
33
35
|
assert(viewmodel.model.persisted?)
|
34
36
|
refute(viewmodel.model.new_record?)
|
35
37
|
end
|
36
38
|
|
37
|
-
it
|
39
|
+
it 'can clone the model' do
|
38
40
|
clone_model = Cloner.new.clone(viewmodel)
|
39
41
|
assert(clone_model.new_record?)
|
40
42
|
assert_nil(clone_model.id)
|
@@ -45,75 +47,75 @@ class ViewModel::ActiveRecord
|
|
45
47
|
end
|
46
48
|
|
47
49
|
class IgnoreParentCloner < Cloner
|
48
|
-
def visit_model_view(
|
50
|
+
def visit_model_view(_node, _model)
|
49
51
|
ignore!
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
|
-
it
|
55
|
+
it 'can ignore a model' do
|
54
56
|
clone_model = IgnoreParentCloner.new.clone(viewmodel)
|
55
57
|
assert_nil(clone_model)
|
56
58
|
end
|
57
59
|
|
58
60
|
class IgnoreAllCloner < Cloner
|
59
|
-
def pre_visit(
|
61
|
+
def pre_visit(_node, _model)
|
60
62
|
ignore!
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
|
-
it
|
66
|
+
it 'can ignore a model in pre-visit' do
|
65
67
|
clone_model = IgnoreAllCloner.new.clone(viewmodel)
|
66
68
|
assert_nil(clone_model)
|
67
69
|
end
|
68
70
|
|
69
71
|
class AlterAttributeCloner < Cloner
|
70
|
-
def visit_model_view(
|
71
|
-
model.name =
|
72
|
+
def visit_model_view(_node, model)
|
73
|
+
model.name = 'changed'
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
75
|
-
it
|
77
|
+
it 'can alter a model attribute' do
|
76
78
|
clone_model = AlterAttributeCloner.new.clone(viewmodel)
|
77
79
|
assert(clone_model.new_record?)
|
78
80
|
assert_nil(clone_model.id)
|
79
|
-
assert_equal(
|
80
|
-
refute_equal(
|
81
|
+
assert_equal('changed', clone_model.name)
|
82
|
+
refute_equal('changed', model.name)
|
81
83
|
assert_equal(model.nonview, clone_model.nonview)
|
82
84
|
clone_model.save!
|
83
85
|
refute_equal(model, clone_model)
|
84
86
|
end
|
85
87
|
|
86
88
|
class PostAlterAttributeCloner < Cloner
|
87
|
-
def end_visit_model_view(
|
88
|
-
model.name =
|
89
|
+
def end_visit_model_view(_node, model)
|
90
|
+
model.name = 'changed'
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
92
|
-
it
|
94
|
+
it 'can alter a model attribute post-visit' do
|
93
95
|
clone_model = PostAlterAttributeCloner.new.clone(viewmodel)
|
94
96
|
assert(clone_model.new_record?)
|
95
97
|
assert_nil(clone_model.id)
|
96
|
-
assert_equal(
|
97
|
-
refute_equal(
|
98
|
+
assert_equal('changed', clone_model.name)
|
99
|
+
refute_equal('changed', model.name)
|
98
100
|
assert_equal(model.nonview, clone_model.nonview)
|
99
101
|
clone_model.save!
|
100
102
|
refute_equal(model, clone_model)
|
101
103
|
end
|
102
104
|
end
|
103
105
|
|
104
|
-
describe
|
106
|
+
describe 'with a child' do
|
105
107
|
def new_child_model
|
106
|
-
child_model_class.new(name:
|
108
|
+
child_model_class.new(name: 'b')
|
107
109
|
end
|
108
110
|
|
109
111
|
def new_model
|
110
|
-
model_class.new(name:
|
112
|
+
model_class.new(name: 'a', child: new_child_model)
|
111
113
|
end
|
112
114
|
|
113
115
|
module BehavesLikeConstructingAChild
|
114
116
|
extend ActiveSupport::Concern
|
115
117
|
included do
|
116
|
-
it
|
118
|
+
it 'persists the test setup' do
|
117
119
|
assert(viewmodel.model.persisted?)
|
118
120
|
refute(viewmodel.model.new_record?)
|
119
121
|
assert(viewmodel.model.child.persisted?)
|
@@ -123,7 +125,7 @@ class ViewModel::ActiveRecord
|
|
123
125
|
end
|
124
126
|
|
125
127
|
class IgnoreChildAssociationCloner < Cloner
|
126
|
-
def visit_model_view(
|
128
|
+
def visit_model_view(_node, _model)
|
127
129
|
ignore_association!(:child)
|
128
130
|
end
|
129
131
|
end
|
@@ -131,7 +133,7 @@ class ViewModel::ActiveRecord
|
|
131
133
|
module BehavesLikeCloningAChild
|
132
134
|
extend ActiveSupport::Concern
|
133
135
|
included do
|
134
|
-
it
|
136
|
+
it 'can clone the model and child' do
|
135
137
|
clone_model = Cloner.new.clone(viewmodel)
|
136
138
|
|
137
139
|
assert(clone_model.new_record?)
|
@@ -148,7 +150,7 @@ class ViewModel::ActiveRecord
|
|
148
150
|
refute_equal(model.child, clone_model.child)
|
149
151
|
end
|
150
152
|
|
151
|
-
it
|
153
|
+
it 'can ignore the child association' do
|
152
154
|
clone_model = IgnoreChildAssociationCloner.new.clone(viewmodel)
|
153
155
|
|
154
156
|
assert(clone_model.new_record?)
|
@@ -160,66 +162,67 @@ class ViewModel::ActiveRecord
|
|
160
162
|
end
|
161
163
|
end
|
162
164
|
|
163
|
-
describe
|
165
|
+
describe 'as belongs_to' do
|
164
166
|
include ViewModelSpecHelpers::ParentAndBelongsToChild
|
165
167
|
include BehavesLikeConstructingAChild
|
166
168
|
include BehavesLikeCloningAChild
|
167
169
|
end
|
168
170
|
|
169
|
-
describe
|
171
|
+
describe 'as has_one' do
|
170
172
|
include ViewModelSpecHelpers::ParentAndHasOneChild
|
171
173
|
include BehavesLikeConstructingAChild
|
172
174
|
include BehavesLikeCloningAChild
|
173
175
|
end
|
174
176
|
|
175
|
-
describe
|
177
|
+
describe 'as belongs_to shared child' do
|
176
178
|
include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
|
177
179
|
include BehavesLikeConstructingAChild
|
178
|
-
it "can clone the model but not the child" do
|
179
|
-
clone_model = Cloner.new.clone(viewmodel)
|
180
180
|
|
181
|
-
|
182
|
-
|
183
|
-
assert_equal(model.name, clone_model.name)
|
181
|
+
it 'can clone the model but not the child' do
|
182
|
+
clone_model = Cloner.new.clone(viewmodel)
|
184
183
|
|
185
|
-
|
186
|
-
|
187
|
-
|
184
|
+
assert(clone_model.new_record?)
|
185
|
+
assert_nil(clone_model.id)
|
186
|
+
assert_equal(model.name, clone_model.name)
|
188
187
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
188
|
+
clone_child = clone_model.child
|
189
|
+
refute(clone_child.new_record?)
|
190
|
+
assert_equal(model.child, clone_child)
|
191
|
+
|
192
|
+
clone_model.save!
|
193
|
+
refute_equal(model, clone_model)
|
194
|
+
assert_equal(model.child, clone_model.child)
|
195
|
+
end
|
193
196
|
end
|
194
197
|
end
|
195
198
|
|
196
199
|
class IgnoreChildrenAssociationCloner < Cloner
|
197
|
-
def visit_model_view(
|
200
|
+
def visit_model_view(_node, _model)
|
198
201
|
ignore_association!(:children)
|
199
202
|
end
|
200
203
|
end
|
201
204
|
|
202
|
-
describe
|
205
|
+
describe 'with has_many children' do
|
203
206
|
include ViewModelSpecHelpers::ParentAndHasManyChildren
|
204
207
|
def new_child_models
|
205
|
-
[
|
208
|
+
['b', 'c'].map { |n| child_model_class.new(name: n) }
|
206
209
|
end
|
207
210
|
|
208
211
|
def new_model
|
209
|
-
model_class.new(name:
|
212
|
+
model_class.new(name: 'a', children: new_child_models)
|
210
213
|
end
|
211
214
|
|
212
|
-
it
|
215
|
+
it 'persists the test setup' do
|
213
216
|
assert(viewmodel.model.persisted?)
|
214
217
|
refute(viewmodel.model.new_record?)
|
215
218
|
assert_equal(2, viewmodel.model.children.size)
|
216
|
-
viewmodel.model.children.each do |
|
219
|
+
viewmodel.model.children.each do |child|
|
217
220
|
assert(child.persisted?)
|
218
221
|
refute(child.new_record?)
|
219
222
|
end
|
220
223
|
end
|
221
224
|
|
222
|
-
it
|
225
|
+
it 'can clone the model' do
|
223
226
|
clone_model = Cloner.new.clone(viewmodel)
|
224
227
|
|
225
228
|
assert(clone_model.new_record?)
|
@@ -244,9 +247,10 @@ class ViewModel::ActiveRecord
|
|
244
247
|
class IgnoreFirstChildCloner < Cloner
|
245
248
|
def initialize
|
246
249
|
@ignored_first = false
|
250
|
+
super
|
247
251
|
end
|
248
252
|
|
249
|
-
def visit_child_view(
|
253
|
+
def visit_child_view(_node, _model)
|
250
254
|
unless @ignored_first
|
251
255
|
@ignored_first = true
|
252
256
|
ignore!
|
@@ -254,7 +258,7 @@ class ViewModel::ActiveRecord
|
|
254
258
|
end
|
255
259
|
end
|
256
260
|
|
257
|
-
it
|
261
|
+
it 'can ignore subset of children' do
|
258
262
|
clone_model = IgnoreFirstChildCloner.new.clone(viewmodel)
|
259
263
|
|
260
264
|
assert(clone_model.new_record?)
|
@@ -265,7 +269,7 @@ class ViewModel::ActiveRecord
|
|
265
269
|
assert_equal(model.children[1].name, clone_model.children[0].name)
|
266
270
|
end
|
267
271
|
|
268
|
-
it
|
272
|
+
it 'can ignore the children association' do
|
269
273
|
clone_model = IgnoreChildrenAssociationCloner.new.clone(viewmodel)
|
270
274
|
|
271
275
|
assert(clone_model.new_record?)
|
@@ -276,19 +280,19 @@ class ViewModel::ActiveRecord
|
|
276
280
|
end
|
277
281
|
end
|
278
282
|
|
279
|
-
describe
|
283
|
+
describe 'with has_many_through shared children' do
|
280
284
|
include ViewModelSpecHelpers::ParentAndHasManyThroughChildren
|
281
285
|
def new_model_children
|
282
|
-
[
|
286
|
+
['b', 'c'].map.with_index do |n, i|
|
283
287
|
join_model_class.new(child: child_model_class.new(name: n), position: i)
|
284
288
|
end
|
285
289
|
end
|
286
290
|
|
287
291
|
def new_model
|
288
|
-
model_class.new(
|
292
|
+
model_class.new(name: 'a', model_children: new_model_children)
|
289
293
|
end
|
290
294
|
|
291
|
-
it
|
295
|
+
it 'persists the test setup' do
|
292
296
|
assert(viewmodel.model.persisted?)
|
293
297
|
refute(viewmodel.model.new_record?)
|
294
298
|
assert_equal(2, viewmodel.model.model_children.size)
|
@@ -301,7 +305,7 @@ class ViewModel::ActiveRecord
|
|
301
305
|
end
|
302
306
|
end
|
303
307
|
|
304
|
-
it
|
308
|
+
it 'can clone the model and join model but not the child' do
|
305
309
|
clone_model = Cloner.new.clone(viewmodel)
|
306
310
|
|
307
311
|
assert(clone_model.new_record?)
|
@@ -325,7 +329,7 @@ class ViewModel::ActiveRecord
|
|
325
329
|
end
|
326
330
|
end
|
327
331
|
|
328
|
-
it
|
332
|
+
it 'can ignore the children association' do
|
329
333
|
clone_model = IgnoreChildrenAssociationCloner.new.clone(viewmodel)
|
330
334
|
|
331
335
|
assert(clone_model.new_record?)
|