iknow_view_models 2.8.4
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 +7 -0
- data/.circleci/config.yml +115 -0
- data/.gitignore +36 -0
- data/.travis.yml +31 -0
- data/Appraisals +9 -0
- data/Gemfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +19 -0
- data/Rakefile +21 -0
- data/appveyor.yml +22 -0
- data/gemfiles/rails_5_2.gemfile +15 -0
- data/gemfiles/rails_6_0_beta.gemfile +15 -0
- data/iknow_view_models.gemspec +49 -0
- data/lib/iknow_view_models.rb +12 -0
- data/lib/iknow_view_models/railtie.rb +8 -0
- data/lib/iknow_view_models/version.rb +5 -0
- data/lib/view_model.rb +333 -0
- data/lib/view_model/access_control.rb +154 -0
- data/lib/view_model/access_control/composed.rb +216 -0
- data/lib/view_model/access_control/open.rb +13 -0
- data/lib/view_model/access_control/read_only.rb +13 -0
- data/lib/view_model/access_control/tree.rb +264 -0
- data/lib/view_model/access_control_error.rb +10 -0
- data/lib/view_model/active_record.rb +383 -0
- data/lib/view_model/active_record/association_data.rb +178 -0
- data/lib/view_model/active_record/association_manipulation.rb +389 -0
- data/lib/view_model/active_record/cache.rb +265 -0
- data/lib/view_model/active_record/cache/cacheable_view.rb +51 -0
- data/lib/view_model/active_record/cloner.rb +113 -0
- data/lib/view_model/active_record/collection_nested_controller.rb +100 -0
- data/lib/view_model/active_record/controller.rb +77 -0
- data/lib/view_model/active_record/controller_base.rb +185 -0
- data/lib/view_model/active_record/nested_controller_base.rb +93 -0
- data/lib/view_model/active_record/singular_nested_controller.rb +34 -0
- data/lib/view_model/active_record/update_context.rb +252 -0
- data/lib/view_model/active_record/update_data.rb +749 -0
- data/lib/view_model/active_record/update_operation.rb +810 -0
- data/lib/view_model/active_record/visitor.rb +77 -0
- data/lib/view_model/after_transaction_runner.rb +29 -0
- data/lib/view_model/callbacks.rb +219 -0
- data/lib/view_model/changes.rb +62 -0
- data/lib/view_model/config.rb +29 -0
- data/lib/view_model/controller.rb +142 -0
- data/lib/view_model/deserialization_error.rb +437 -0
- data/lib/view_model/deserialize_context.rb +16 -0
- data/lib/view_model/error.rb +191 -0
- data/lib/view_model/error_view.rb +35 -0
- data/lib/view_model/record.rb +367 -0
- data/lib/view_model/record/attribute_data.rb +48 -0
- data/lib/view_model/reference.rb +31 -0
- data/lib/view_model/references.rb +48 -0
- data/lib/view_model/registry.rb +73 -0
- data/lib/view_model/schemas.rb +45 -0
- data/lib/view_model/serialization_error.rb +10 -0
- data/lib/view_model/serialize_context.rb +118 -0
- data/lib/view_model/test_helpers.rb +103 -0
- data/lib/view_model/test_helpers/arvm_builder.rb +111 -0
- data/lib/view_model/traversal_context.rb +126 -0
- data/lib/view_model/utils.rb +24 -0
- data/lib/view_model/utils/collections.rb +49 -0
- data/test/helpers/arvm_test_models.rb +59 -0
- data/test/helpers/arvm_test_utilities.rb +187 -0
- data/test/helpers/callback_tracer.rb +27 -0
- data/test/helpers/controller_test_helpers.rb +270 -0
- data/test/helpers/match_enumerator.rb +58 -0
- data/test/helpers/query_logging.rb +71 -0
- data/test/helpers/test_access_control.rb +56 -0
- data/test/helpers/viewmodel_spec_helpers.rb +326 -0
- data/test/unit/view_model/access_control_test.rb +769 -0
- data/test/unit/view_model/active_record/alias_test.rb +35 -0
- data/test/unit/view_model/active_record/belongs_to_test.rb +376 -0
- data/test/unit/view_model/active_record/cache_test.rb +351 -0
- data/test/unit/view_model/active_record/cloner_test.rb +313 -0
- data/test/unit/view_model/active_record/controller_test.rb +561 -0
- data/test/unit/view_model/active_record/counter_test.rb +80 -0
- data/test/unit/view_model/active_record/customization_test.rb +388 -0
- data/test/unit/view_model/active_record/has_many_test.rb +957 -0
- data/test/unit/view_model/active_record/has_many_through_poly_test.rb +269 -0
- data/test/unit/view_model/active_record/has_many_through_test.rb +736 -0
- data/test/unit/view_model/active_record/has_one_test.rb +334 -0
- data/test/unit/view_model/active_record/namespacing_test.rb +75 -0
- data/test/unit/view_model/active_record/optional_attribute_view_test.rb +58 -0
- data/test/unit/view_model/active_record/poly_test.rb +320 -0
- data/test/unit/view_model/active_record/shared_test.rb +285 -0
- data/test/unit/view_model/active_record/version_test.rb +121 -0
- data/test/unit/view_model/active_record_test.rb +542 -0
- data/test/unit/view_model/callbacks_test.rb +582 -0
- data/test/unit/view_model/deserialization_error/unique_violation_test.rb +73 -0
- data/test/unit/view_model/record_test.rb +524 -0
- data/test/unit/view_model/traversal_context_test.rb +371 -0
- data/test/unit/view_model_test.rb +62 -0
- metadata +490 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
require_relative "../../../helpers/arvm_test_utilities.rb"
|
|
2
|
+
require_relative "../../../helpers/arvm_test_models.rb"
|
|
3
|
+
|
|
4
|
+
require "minitest/autorun"
|
|
5
|
+
|
|
6
|
+
require "view_model/active_record"
|
|
7
|
+
|
|
8
|
+
class ViewModel::ActiveRecord::HasOneTest < ActiveSupport::TestCase
|
|
9
|
+
include ARVMTestUtilities
|
|
10
|
+
|
|
11
|
+
def self.build_target(arvm_test_case)
|
|
12
|
+
arvm_test_case.build_viewmodel(:Target) do
|
|
13
|
+
define_schema do |t|
|
|
14
|
+
t.string :text
|
|
15
|
+
t.references :parent, foreign_key: true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
define_model do
|
|
19
|
+
belongs_to :parent, inverse_of: :target
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
define_viewmodel do
|
|
23
|
+
attributes :text
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def self.build_parent(arvm_test_case)
|
|
30
|
+
arvm_test_case.build_viewmodel(:Parent) do
|
|
31
|
+
define_schema do |t|
|
|
32
|
+
t.string :name
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
define_model do
|
|
36
|
+
has_one :target, dependent: :destroy, inverse_of: :parent
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
define_viewmodel do
|
|
40
|
+
attributes :name
|
|
41
|
+
associations :target
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def before_all
|
|
47
|
+
super
|
|
48
|
+
|
|
49
|
+
self.class.build_parent(self)
|
|
50
|
+
self.class.build_target(self)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def setup
|
|
54
|
+
super
|
|
55
|
+
|
|
56
|
+
# TODO make a `has_list?` that allows a parent to set all children as an array
|
|
57
|
+
@parent1 = Parent.new(name: "p1",
|
|
58
|
+
target: Target.new(text: "p1t"))
|
|
59
|
+
@parent1.save!
|
|
60
|
+
|
|
61
|
+
@parent2 = Parent.new(name: "p2",
|
|
62
|
+
target: Target.new(text: "p2t"))
|
|
63
|
+
|
|
64
|
+
@parent2.save!
|
|
65
|
+
|
|
66
|
+
enable_logging!
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_loading_batching
|
|
70
|
+
log_queries do
|
|
71
|
+
serialize(ParentView.load)
|
|
72
|
+
end
|
|
73
|
+
assert_equal(['Parent Load', 'Target Load'],
|
|
74
|
+
logged_load_queries)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_create_from_view
|
|
78
|
+
view = {
|
|
79
|
+
"_type" => "Parent",
|
|
80
|
+
"name" => "p",
|
|
81
|
+
"target" => { "_type" => "Target", "text" => "t" },
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
pv = ParentView.deserialize_from_view(view)
|
|
85
|
+
p = pv.model
|
|
86
|
+
|
|
87
|
+
assert(!p.changed?)
|
|
88
|
+
assert(!p.new_record?)
|
|
89
|
+
|
|
90
|
+
assert_equal("p", p.name)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
assert(p.target.present?)
|
|
94
|
+
assert_equal("t", p.target.text)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_serialize_view
|
|
98
|
+
view, _refs = serialize_with_references(ParentView.new(@parent1))
|
|
99
|
+
assert_equal({ "_type" => "Parent",
|
|
100
|
+
"_version" => 1,
|
|
101
|
+
"id" => @parent1.id,
|
|
102
|
+
"name" => @parent1.name,
|
|
103
|
+
"target" => { "_type" => "Target",
|
|
104
|
+
"_version" => 1,
|
|
105
|
+
"id" => @parent1.target.id,
|
|
106
|
+
"text" => @parent1.target.text } },
|
|
107
|
+
view)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_swap_has_one
|
|
111
|
+
@parent1.update(target: t1 = Target.new)
|
|
112
|
+
@parent2.update(target: t2 = Target.new)
|
|
113
|
+
|
|
114
|
+
deserialize_context = ViewModelBase.new_deserialize_context
|
|
115
|
+
|
|
116
|
+
ParentView.deserialize_from_view(
|
|
117
|
+
[update_hash_for(ParentView, @parent1) { |p| p['target'] = update_hash_for(TargetView, t2) },
|
|
118
|
+
update_hash_for(ParentView, @parent2) { |p| p['target'] = update_hash_for(TargetView, t1) }],
|
|
119
|
+
deserialize_context: deserialize_context)
|
|
120
|
+
|
|
121
|
+
assert_equal(Set.new([ViewModel::Reference.new(ParentView, @parent1.id),
|
|
122
|
+
ViewModel::Reference.new(ParentView, @parent2.id)]),
|
|
123
|
+
deserialize_context.valid_edit_refs.to_set)
|
|
124
|
+
|
|
125
|
+
@parent1.reload
|
|
126
|
+
@parent2.reload
|
|
127
|
+
|
|
128
|
+
assert_equal(@parent1.target, t2)
|
|
129
|
+
assert_equal(@parent2.target, t1)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def test_has_one_create_nil
|
|
133
|
+
view = { '_type' => 'Parent', 'name' => 'p', 'target' => nil }
|
|
134
|
+
pv = ParentView.deserialize_from_view(view)
|
|
135
|
+
assert_nil(pv.model.target)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_has_one_create
|
|
139
|
+
@parent1.update(target: nil)
|
|
140
|
+
|
|
141
|
+
alter_by_view!(ParentView, @parent1) do |view, refs|
|
|
142
|
+
view['target'] = { '_type' => 'Target', 'text' => 't' }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
assert_equal('t', @parent1.target.text)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def test_has_one_update
|
|
149
|
+
alter_by_view!(ParentView, @parent1) do |view, refs|
|
|
150
|
+
view['target']['text'] = "hello"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
assert_equal('hello', @parent1.target.text)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def test_has_one_destroy
|
|
157
|
+
old_target = @parent1.target
|
|
158
|
+
alter_by_view!(ParentView, @parent1) do |view, refs|
|
|
159
|
+
view['target'] = nil
|
|
160
|
+
end
|
|
161
|
+
assert(Target.where(id: old_target.id).blank?)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_has_one_move_and_replace
|
|
165
|
+
old_parent1_target = @parent1.target
|
|
166
|
+
old_parent2_target = @parent2.target
|
|
167
|
+
|
|
168
|
+
alter_by_view!(ParentView, [@parent1, @parent2]) do |(p1, p2), refs|
|
|
169
|
+
p2['target'] = p1['target']
|
|
170
|
+
p1['target'] = nil
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
assert(@parent1.target.blank?)
|
|
174
|
+
assert_equal(old_parent1_target, @parent2.target)
|
|
175
|
+
assert(Target.where(id: old_parent2_target).blank?)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def test_has_one_cannot_duplicate_unreleased_child
|
|
179
|
+
# p2 shouldn't be able to copy p1's target
|
|
180
|
+
assert_raises(ViewModel::DeserializationError::DuplicateNodes) do
|
|
181
|
+
alter_by_view!(ParentView, [@parent1, @parent2]) do |(p1, p2), _refs|
|
|
182
|
+
p2['target'] = p1['target'].dup
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def test_has_one_cannot_duplicate_implicitly_unreleased_child
|
|
188
|
+
# p2 shouldn't be able to copy p1's target, even when p1 doesn't explicitly
|
|
189
|
+
# specify the association
|
|
190
|
+
assert_raises(ViewModel::DeserializationError::ParentNotFound) do
|
|
191
|
+
alter_by_view!(ParentView, [@parent1, @parent2]) do |(p1, p2), _refs|
|
|
192
|
+
p2['target'] = p1['target']
|
|
193
|
+
p1.delete('target')
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def test_has_one_cannot_take_from_outside_tree
|
|
199
|
+
t3 = Parent.create(target: Target.new(text: 'hi')).target
|
|
200
|
+
|
|
201
|
+
assert_raises(ViewModel::DeserializationError::ParentNotFound) do
|
|
202
|
+
alter_by_view!(ParentView, [@parent1]) do |(p1), _refs|
|
|
203
|
+
p1['target'] = update_hash_for(TargetView, t3)
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def test_has_one_cannot_take_unparented_from_outside_tree
|
|
209
|
+
t3 = Target.create(text: 'hi') # no parent
|
|
210
|
+
|
|
211
|
+
assert_raises(ViewModel::DeserializationError::ParentNotFound) do
|
|
212
|
+
alter_by_view!(ParentView, @parent1) do |p1, _refs|
|
|
213
|
+
p1['target'] = update_hash_for(TargetView, t3)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def test_bad_single_association
|
|
219
|
+
view = {
|
|
220
|
+
"_type" => "Parent",
|
|
221
|
+
"target" => []
|
|
222
|
+
}
|
|
223
|
+
ex = assert_raises(ViewModel::DeserializationError::InvalidSyntax) do
|
|
224
|
+
ParentView.deserialize_from_view(view)
|
|
225
|
+
end
|
|
226
|
+
assert_match(/not an object/, ex.message)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
class RenameTest < ActiveSupport::TestCase
|
|
231
|
+
include ARVMTestUtilities
|
|
232
|
+
|
|
233
|
+
def before_all
|
|
234
|
+
super
|
|
235
|
+
|
|
236
|
+
build_viewmodel(:Parent) do
|
|
237
|
+
define_schema do |t|
|
|
238
|
+
t.string :name
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
define_model do
|
|
242
|
+
has_one :target, dependent: :destroy, inverse_of: :parent
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
define_viewmodel do
|
|
246
|
+
attributes :name
|
|
247
|
+
association :target, as: :something_else
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
ViewModel::ActiveRecord::HasOneTest.build_target(self)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
def setup
|
|
255
|
+
super
|
|
256
|
+
|
|
257
|
+
@parent = Parent.create(target: Target.new(text: 'target text'))
|
|
258
|
+
|
|
259
|
+
enable_logging!
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
def test_dependencies
|
|
263
|
+
root_updates, _ref_updates = ViewModel::ActiveRecord::UpdateData.parse_hashes([{ '_type' => 'Parent', 'something_else' => nil }])
|
|
264
|
+
assert_equal(DeepPreloader::Spec.new('target' => DeepPreloader::Spec.new), root_updates.first.preload_dependencies)
|
|
265
|
+
assert_equal({ 'something_else' => {} }, root_updates.first.updated_associations)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def test_renamed_roundtrip
|
|
269
|
+
alter_by_view!(ParentView, @parent) do |view, refs|
|
|
270
|
+
assert_equal({ 'id' => @parent.target.id,
|
|
271
|
+
'_type' => 'Target',
|
|
272
|
+
'_version' => 1,
|
|
273
|
+
'text' => 'target text' },
|
|
274
|
+
view['something_else'])
|
|
275
|
+
view['something_else']['text'] = 'target new text'
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
assert_equal('target new text', @parent.target.text)
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
class FreedChildrenTest < ActiveSupport::TestCase
|
|
283
|
+
include ARVMTestUtilities
|
|
284
|
+
|
|
285
|
+
def before_all
|
|
286
|
+
build_viewmodel(:Aye) do
|
|
287
|
+
define_schema do |t|
|
|
288
|
+
t.references :bee
|
|
289
|
+
end
|
|
290
|
+
define_model do
|
|
291
|
+
belongs_to :bee, inverse_of: :aye, dependent: :destroy
|
|
292
|
+
end
|
|
293
|
+
define_viewmodel do
|
|
294
|
+
association :bee
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
build_viewmodel(:Bee) do
|
|
299
|
+
define_schema do |t|
|
|
300
|
+
end
|
|
301
|
+
define_model do
|
|
302
|
+
has_one :aye, inverse_of: :bee
|
|
303
|
+
has_one :cee, inverse_of: :bee, dependent: :destroy
|
|
304
|
+
end
|
|
305
|
+
define_viewmodel do
|
|
306
|
+
association :cee
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
build_viewmodel(:Cee) do
|
|
311
|
+
define_schema do |t|
|
|
312
|
+
t.references :bee
|
|
313
|
+
end
|
|
314
|
+
define_model do
|
|
315
|
+
belongs_to :bee, inverse_of: :cee
|
|
316
|
+
end
|
|
317
|
+
define_viewmodel do
|
|
318
|
+
end
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
def test_reclaim_grandchild_from_deleted_child
|
|
323
|
+
skip 'Issue #8'
|
|
324
|
+
|
|
325
|
+
model = Aye.create(bee: Bee.new(cee: Cee.new))
|
|
326
|
+
|
|
327
|
+
# This test currently fails because we only release the top of the deleted
|
|
328
|
+
# subtree to the release pool, and so its children cannot be reclaimed.
|
|
329
|
+
alter_by_view!(AyeView, model) do |view, _refs|
|
|
330
|
+
view['bee'].delete('id')
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require "minitest/autorun"
|
|
2
|
+
require "minitest/unit"
|
|
3
|
+
require "minitest/hooks"
|
|
4
|
+
|
|
5
|
+
require_relative "../../../helpers/arvm_test_utilities.rb"
|
|
6
|
+
require_relative "../../../helpers/arvm_test_models.rb"
|
|
7
|
+
require_relative "../../../helpers/viewmodel_spec_helpers.rb"
|
|
8
|
+
|
|
9
|
+
require "view_model"
|
|
10
|
+
require "view_model/active_record"
|
|
11
|
+
|
|
12
|
+
module NSTest
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class ViewModel::ActiveRecord::NamespacingTest < ActiveSupport::TestCase
|
|
16
|
+
include ViewModelSpecHelpers::ParentAndHasOneChild
|
|
17
|
+
extend Minitest::Spec::DSL
|
|
18
|
+
|
|
19
|
+
def namespace
|
|
20
|
+
NSTest
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def model_attributes
|
|
24
|
+
parent_attrs = super
|
|
25
|
+
|
|
26
|
+
ViewModel::TestHelpers::ARVMBuilder::Spec.new(
|
|
27
|
+
schema: parent_attrs.schema,
|
|
28
|
+
viewmodel: parent_attrs.viewmodel,
|
|
29
|
+
model: ->(_) {
|
|
30
|
+
has_one :child, inverse_of: :model, class_name: "NSTest::Child", dependent: :destroy
|
|
31
|
+
})
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe 'inference' do
|
|
35
|
+
it "assigns a transformed view name from a namespaced class" do
|
|
36
|
+
assert_equal("NSTest.Model", viewmodel_class.view_name)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "can look up a viewmodel by inference from an association to a namespaced model" do
|
|
40
|
+
child_viewmodel_class # test depends on child_viewmodel_class
|
|
41
|
+
|
|
42
|
+
assert_equal(viewmodel_class._association_data('child').viewmodel_class,
|
|
43
|
+
child_viewmodel_class)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "can infer the model class from a namespaced view class name" do
|
|
47
|
+
assert_equal(viewmodel_class.model_class, model_class)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe 'access control' do
|
|
52
|
+
include ARVMTestUtilities
|
|
53
|
+
|
|
54
|
+
it 'can apply access control policy for namespaced classes' do
|
|
55
|
+
_viewmodel_class = viewmodel_class
|
|
56
|
+
|
|
57
|
+
access_control_class =
|
|
58
|
+
Class.new(ViewModel::AccessControl::Tree) do
|
|
59
|
+
view(_viewmodel_class.view_name) do
|
|
60
|
+
visible_unless!("VETO-ERROR-MESSAGE") { true }
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
child_viewmodel_class # test depends on child_viewmodel_class
|
|
65
|
+
|
|
66
|
+
serialize_context = viewmodel_class.new_serialize_context(
|
|
67
|
+
access_control: access_control_class.new)
|
|
68
|
+
|
|
69
|
+
refute_serializes(viewmodel_class,
|
|
70
|
+
model_class.create!,
|
|
71
|
+
"VETO-ERROR-MESSAGE",
|
|
72
|
+
serialize_context: serialize_context)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
require_relative "../../../helpers/arvm_test_utilities.rb"
|
|
2
|
+
require_relative "../../../helpers/arvm_test_models.rb"
|
|
3
|
+
|
|
4
|
+
require "minitest/autorun"
|
|
5
|
+
|
|
6
|
+
require "view_model/active_record"
|
|
7
|
+
|
|
8
|
+
class ViewModel::ActiveRecord::AttributeViewTest < ActiveSupport::TestCase
|
|
9
|
+
include ARVMTestUtilities
|
|
10
|
+
|
|
11
|
+
def before_all
|
|
12
|
+
super
|
|
13
|
+
|
|
14
|
+
build_viewmodel(:Thing) do
|
|
15
|
+
define_schema do |t|
|
|
16
|
+
t.integer :a
|
|
17
|
+
t.integer :b
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
define_model do
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
define_viewmodel do
|
|
24
|
+
attribute :a
|
|
25
|
+
attribute :b, optional: true
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def setup
|
|
31
|
+
super
|
|
32
|
+
@thing = Thing.create!(a: 1, b: 2)
|
|
33
|
+
|
|
34
|
+
@skel = { "_type" => "Thing",
|
|
35
|
+
"_version" => 1,
|
|
36
|
+
"id" => @thing.id }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_optional_not_serialized
|
|
40
|
+
view, _refs = serialize_with_references(ThingView.new(@thing))
|
|
41
|
+
|
|
42
|
+
assert_equal(@skel.merge("a" => 1), view)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def test_optional_included
|
|
46
|
+
view, _refs = serialize_with_references(ThingView.new(@thing),
|
|
47
|
+
serialize_context: ThingView.new_serialize_context(include: :b))
|
|
48
|
+
|
|
49
|
+
assert_equal(@skel.merge("a" => 1, "b" => 2), view)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_pruned_not_included
|
|
53
|
+
view, _refs = serialize_with_references(ThingView.new(@thing),
|
|
54
|
+
serialize_context: ThingView.new_serialize_context(include: :b, prune: :a))
|
|
55
|
+
|
|
56
|
+
assert_equal(@skel.merge("b" => 2), view)
|
|
57
|
+
end
|
|
58
|
+
end
|