jsonapi-resources 0.10.6 → 0.11.0.beta2
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/LICENSE.txt +1 -1
- data/README.md +39 -2
- data/lib/generators/jsonapi/controller_generator.rb +2 -0
- data/lib/generators/jsonapi/resource_generator.rb +2 -0
- data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +3 -2
- data/lib/jsonapi/active_relation/join_manager.rb +30 -18
- data/lib/jsonapi/active_relation/join_manager_v10.rb +305 -0
- data/lib/jsonapi/active_relation_retrieval.rb +885 -0
- data/lib/jsonapi/active_relation_retrieval_v09.rb +715 -0
- data/lib/jsonapi/{active_relation_resource.rb → active_relation_retrieval_v10.rb} +113 -135
- data/lib/jsonapi/acts_as_resource_controller.rb +49 -49
- data/lib/jsonapi/cached_response_fragment.rb +4 -2
- data/lib/jsonapi/callbacks.rb +2 -0
- data/lib/jsonapi/compiled_json.rb +2 -0
- data/lib/jsonapi/configuration.rb +35 -15
- data/lib/jsonapi/error.rb +2 -0
- data/lib/jsonapi/error_codes.rb +2 -0
- data/lib/jsonapi/exceptions.rb +2 -0
- data/lib/jsonapi/formatter.rb +2 -0
- data/lib/jsonapi/include_directives.rb +77 -19
- data/lib/jsonapi/link_builder.rb +2 -0
- data/lib/jsonapi/mime_types.rb +6 -10
- data/lib/jsonapi/naive_cache.rb +2 -0
- data/lib/jsonapi/operation.rb +2 -0
- data/lib/jsonapi/operation_result.rb +2 -0
- data/lib/jsonapi/paginator.rb +2 -0
- data/lib/jsonapi/path.rb +2 -0
- data/lib/jsonapi/path_segment.rb +4 -2
- data/lib/jsonapi/processor.rb +95 -140
- data/lib/jsonapi/relationship.rb +89 -35
- data/lib/jsonapi/{request_parser.rb → request.rb} +157 -164
- data/lib/jsonapi/resource.rb +7 -2
- data/lib/jsonapi/{basic_resource.rb → resource_common.rb} +187 -88
- data/lib/jsonapi/resource_controller.rb +2 -0
- data/lib/jsonapi/resource_controller_metal.rb +2 -0
- data/lib/jsonapi/resource_fragment.rb +17 -15
- data/lib/jsonapi/resource_identity.rb +6 -0
- data/lib/jsonapi/resource_serializer.rb +20 -4
- data/lib/jsonapi/resource_set.rb +36 -16
- data/lib/jsonapi/resource_tree.rb +191 -0
- data/lib/jsonapi/resources/railtie.rb +3 -1
- data/lib/jsonapi/resources/version.rb +3 -1
- data/lib/jsonapi/response_document.rb +4 -2
- data/lib/jsonapi/routing_ext.rb +4 -2
- data/lib/jsonapi/simple_resource.rb +13 -0
- data/lib/jsonapi-resources.rb +10 -4
- data/lib/tasks/check_upgrade.rake +3 -1
- metadata +47 -15
- data/lib/jsonapi/resource_id_tree.rb +0 -112
data/lib/jsonapi/processor.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JSONAPI
|
2
4
|
class Processor
|
3
5
|
include Callbacks
|
@@ -49,7 +51,7 @@ module JSONAPI
|
|
49
51
|
|
50
52
|
verified_filters = resource_klass.verify_filters(filters, context)
|
51
53
|
|
52
|
-
|
54
|
+
options = {
|
53
55
|
context: context,
|
54
56
|
sort_criteria: sort_criteria,
|
55
57
|
paginator: paginator,
|
@@ -58,11 +60,9 @@ module JSONAPI
|
|
58
60
|
include_directives: include_directives
|
59
61
|
}
|
60
62
|
|
61
|
-
resource_set = find_resource_set(
|
62
|
-
include_directives,
|
63
|
-
find_options)
|
63
|
+
resource_set = find_resource_set(include_directives, options)
|
64
64
|
|
65
|
-
resource_set.populate!(serializer, context,
|
65
|
+
resource_set.populate!(serializer, context, options)
|
66
66
|
|
67
67
|
page_options = result_options
|
68
68
|
if (JSONAPI.configuration.top_level_meta_include_record_count || (paginator && paginator.class.requires_record_count))
|
@@ -79,7 +79,7 @@ module JSONAPI
|
|
79
79
|
page_options[:pagination_params] = paginator.links_page_params(page_options.merge(fetched_resources: resource_set))
|
80
80
|
end
|
81
81
|
|
82
|
-
|
82
|
+
JSONAPI::ResourcesSetOperationResult.new(:ok, resource_set, page_options)
|
83
83
|
end
|
84
84
|
|
85
85
|
def show
|
@@ -90,26 +90,25 @@ module JSONAPI
|
|
90
90
|
|
91
91
|
key = resource_klass.verify_key(id, context)
|
92
92
|
|
93
|
-
|
93
|
+
options = {
|
94
94
|
context: context,
|
95
95
|
fields: fields,
|
96
96
|
filters: { resource_klass._primary_key => key },
|
97
97
|
include_directives: include_directives
|
98
98
|
}
|
99
99
|
|
100
|
-
resource_set = find_resource_set(
|
101
|
-
include_directives,
|
102
|
-
find_options)
|
100
|
+
resource_set = find_resource_set(include_directives, options)
|
103
101
|
|
104
102
|
fail JSONAPI::Exceptions::RecordNotFound.new(id) if resource_set.resource_klasses.empty?
|
105
|
-
resource_set.populate!(serializer, context,
|
103
|
+
resource_set.populate!(serializer, context, options)
|
106
104
|
|
107
|
-
|
105
|
+
JSONAPI::ResourceSetOperationResult.new(:ok, resource_set, result_options)
|
108
106
|
end
|
109
107
|
|
110
108
|
def show_relationship
|
111
109
|
parent_key = params[:parent_key]
|
112
110
|
relationship_type = params[:relationship_type].to_sym
|
111
|
+
relationship = resource_klass._relationship(relationship_type)
|
113
112
|
paginator = params[:paginator]
|
114
113
|
sort_criteria = params[:sort_criteria]
|
115
114
|
include_directives = params[:include_directives]
|
@@ -117,25 +116,26 @@ module JSONAPI
|
|
117
116
|
|
118
117
|
parent_resource = resource_klass.find_by_key(parent_key, context: context)
|
119
118
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
119
|
+
options = {
|
120
|
+
context: context,
|
121
|
+
sort_criteria: sort_criteria,
|
122
|
+
paginator: paginator,
|
123
|
+
fields: fields,
|
124
|
+
include_directives: include_directives
|
126
125
|
}
|
127
126
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
127
|
+
resource_tree = find_related_resource_tree(
|
128
|
+
parent_resource,
|
129
|
+
relationship,
|
130
|
+
options,
|
131
|
+
nil
|
132
|
+
)
|
133
|
+
|
134
|
+
JSONAPI::RelationshipOperationResult.new(:ok,
|
135
|
+
parent_resource,
|
136
|
+
relationship,
|
137
|
+
resource_tree.fragments.keys,
|
138
|
+
result_options)
|
139
139
|
end
|
140
140
|
|
141
141
|
def show_related_resource
|
@@ -146,11 +146,11 @@ module JSONAPI
|
|
146
146
|
serializer = params[:serializer]
|
147
147
|
fields = params[:fields]
|
148
148
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
149
|
+
options = {
|
150
|
+
context: context,
|
151
|
+
fields: fields,
|
152
|
+
filters: {},
|
153
|
+
include_directives: include_directives
|
154
154
|
}
|
155
155
|
|
156
156
|
source_resource = source_klass.find_by_key(source_id, context: context, fields: fields)
|
@@ -158,11 +158,11 @@ module JSONAPI
|
|
158
158
|
resource_set = find_related_resource_set(source_resource,
|
159
159
|
relationship_type,
|
160
160
|
include_directives,
|
161
|
-
|
161
|
+
options)
|
162
162
|
|
163
|
-
resource_set.populate!(serializer, context,
|
163
|
+
resource_set.populate!(serializer, context, options)
|
164
164
|
|
165
|
-
|
165
|
+
JSONAPI::ResourceSetOperationResult.new(:ok, resource_set, result_options)
|
166
166
|
end
|
167
167
|
|
168
168
|
def show_related_resources
|
@@ -178,8 +178,8 @@ module JSONAPI
|
|
178
178
|
|
179
179
|
verified_filters = resource_klass.verify_filters(filters, context)
|
180
180
|
|
181
|
-
|
182
|
-
filters:
|
181
|
+
options = {
|
182
|
+
filters: verified_filters,
|
183
183
|
sort_criteria: sort_criteria,
|
184
184
|
paginator: paginator,
|
185
185
|
fields: fields,
|
@@ -192,19 +192,21 @@ module JSONAPI
|
|
192
192
|
resource_set = find_related_resource_set(source_resource,
|
193
193
|
relationship_type,
|
194
194
|
include_directives,
|
195
|
-
|
195
|
+
options)
|
196
196
|
|
197
|
-
resource_set.populate!(serializer, context,
|
197
|
+
resource_set.populate!(serializer, context, options)
|
198
198
|
|
199
199
|
opts = result_options
|
200
200
|
if ((JSONAPI.configuration.top_level_meta_include_record_count) ||
|
201
|
-
|
202
|
-
|
201
|
+
(paginator && paginator.class.requires_record_count) ||
|
202
|
+
(JSONAPI.configuration.top_level_meta_include_page_count))
|
203
|
+
|
204
|
+
relationship = source_resource.class._relationship(relationship_type)
|
203
205
|
|
204
206
|
opts[:record_count] = source_resource.class.count_related(
|
205
|
-
|
206
|
-
|
207
|
-
|
207
|
+
source_resource,
|
208
|
+
relationship,
|
209
|
+
options)
|
208
210
|
end
|
209
211
|
|
210
212
|
if (JSONAPI.configuration.top_level_meta_include_page_count && opts[:record_count])
|
@@ -219,11 +221,11 @@ module JSONAPI
|
|
219
221
|
{}
|
220
222
|
end
|
221
223
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
224
|
+
JSONAPI::RelatedResourcesSetOperationResult.new(:ok,
|
225
|
+
source_resource,
|
226
|
+
relationship_type,
|
227
|
+
resource_set,
|
228
|
+
opts)
|
227
229
|
end
|
228
230
|
|
229
231
|
def create_resource
|
@@ -235,20 +237,18 @@ module JSONAPI
|
|
235
237
|
resource = resource_klass.create(context)
|
236
238
|
result = resource.replace_fields(data)
|
237
239
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
240
|
+
options = {
|
241
|
+
context: context,
|
242
|
+
fields: fields,
|
243
|
+
filters: { resource_klass._primary_key => resource.id },
|
244
|
+
include_directives: include_directives
|
243
245
|
}
|
244
246
|
|
245
|
-
resource_set = find_resource_set(
|
246
|
-
include_directives,
|
247
|
-
find_options)
|
247
|
+
resource_set = find_resource_set(include_directives, options)
|
248
248
|
|
249
|
-
resource_set.populate!(serializer, context,
|
249
|
+
resource_set.populate!(serializer, context, options)
|
250
250
|
|
251
|
-
|
251
|
+
JSONAPI::ResourceSetOperationResult.new((result == :completed ? :created : :accepted), resource_set, result_options)
|
252
252
|
end
|
253
253
|
|
254
254
|
def remove_resource
|
@@ -257,7 +257,7 @@ module JSONAPI
|
|
257
257
|
resource = resource_klass.find_by_key(resource_id, context: context)
|
258
258
|
result = resource.remove
|
259
259
|
|
260
|
-
|
260
|
+
JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
|
261
261
|
end
|
262
262
|
|
263
263
|
def replace_fields
|
@@ -272,20 +272,18 @@ module JSONAPI
|
|
272
272
|
|
273
273
|
result = resource.replace_fields(data)
|
274
274
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
275
|
+
options = {
|
276
|
+
context: context,
|
277
|
+
fields: fields,
|
278
|
+
filters: { resource_klass._primary_key => resource.id },
|
279
|
+
include_directives: include_directives
|
280
280
|
}
|
281
281
|
|
282
|
-
resource_set = find_resource_set(
|
283
|
-
include_directives,
|
284
|
-
find_options)
|
282
|
+
resource_set = find_resource_set(include_directives, options)
|
285
283
|
|
286
|
-
resource_set.populate!(serializer, context,
|
284
|
+
resource_set.populate!(serializer, context, options)
|
287
285
|
|
288
|
-
|
286
|
+
JSONAPI::ResourceSetOperationResult.new((result == :completed ? :ok : :accepted), resource_set, result_options)
|
289
287
|
end
|
290
288
|
|
291
289
|
def replace_to_one_relationship
|
@@ -296,7 +294,7 @@ module JSONAPI
|
|
296
294
|
resource = resource_klass.find_by_key(resource_id, context: context)
|
297
295
|
result = resource.replace_to_one_link(relationship_type, key_value)
|
298
296
|
|
299
|
-
|
297
|
+
JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
|
300
298
|
end
|
301
299
|
|
302
300
|
def replace_polymorphic_to_one_relationship
|
@@ -308,7 +306,7 @@ module JSONAPI
|
|
308
306
|
resource = resource_klass.find_by_key(resource_id, context: context)
|
309
307
|
result = resource.replace_polymorphic_to_one_link(relationship_type, key_value, key_type)
|
310
308
|
|
311
|
-
|
309
|
+
JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
|
312
310
|
end
|
313
311
|
|
314
312
|
def create_to_many_relationships
|
@@ -319,7 +317,7 @@ module JSONAPI
|
|
319
317
|
resource = resource_klass.find_by_key(resource_id, context: context)
|
320
318
|
result = resource.create_to_many_links(relationship_type, data)
|
321
319
|
|
322
|
-
|
320
|
+
JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
|
323
321
|
end
|
324
322
|
|
325
323
|
def replace_to_many_relationships
|
@@ -330,7 +328,7 @@ module JSONAPI
|
|
330
328
|
resource = resource_klass.find_by_key(resource_id, context: context)
|
331
329
|
result = resource.replace_to_many_links(relationship_type, data)
|
332
330
|
|
333
|
-
|
331
|
+
JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
|
334
332
|
end
|
335
333
|
|
336
334
|
def remove_to_many_relationships
|
@@ -347,7 +345,7 @@ module JSONAPI
|
|
347
345
|
complete = false
|
348
346
|
end
|
349
347
|
end
|
350
|
-
|
348
|
+
JSONAPI::OperationResult.new(complete ? :no_content : :accepted, result_options)
|
351
349
|
end
|
352
350
|
|
353
351
|
def remove_to_one_relationship
|
@@ -357,7 +355,7 @@ module JSONAPI
|
|
357
355
|
resource = resource_klass.find_by_key(resource_id, context: context)
|
358
356
|
result = resource.remove_to_one_link(relationship_type)
|
359
357
|
|
360
|
-
|
358
|
+
JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted, result_options)
|
361
359
|
end
|
362
360
|
|
363
361
|
def result_options
|
@@ -366,91 +364,48 @@ module JSONAPI
|
|
366
364
|
options
|
367
365
|
end
|
368
366
|
|
369
|
-
def find_resource_set(
|
370
|
-
include_related = include_directives
|
367
|
+
def find_resource_set(include_directives, options)
|
368
|
+
include_related = include_directives[:include_related] if include_directives
|
371
369
|
|
372
|
-
|
370
|
+
resource_tree = find_resource_tree(options, include_related)
|
373
371
|
|
374
|
-
JSONAPI::ResourceSet.new(
|
372
|
+
JSONAPI::ResourceSet.new(resource_tree)
|
375
373
|
end
|
376
374
|
|
377
375
|
def find_related_resource_set(resource, relationship_name, include_directives, options)
|
378
|
-
include_related = include_directives
|
376
|
+
include_related = include_directives[:include_related] if include_directives
|
379
377
|
|
380
|
-
|
378
|
+
resource_tree = find_resource_tree_from_relationship(resource, relationship_name, options, include_related)
|
381
379
|
|
382
|
-
JSONAPI::ResourceSet.new(
|
380
|
+
JSONAPI::ResourceSet.new(resource_tree)
|
383
381
|
end
|
384
382
|
|
385
|
-
|
386
|
-
def find_related_resource_id_tree(resource_klass, source_id, relationship_name, find_options, include_related)
|
387
|
-
options = find_options.except(:include_directives)
|
383
|
+
def find_resource_tree(options, include_related)
|
388
384
|
options[:cache] = resource_klass.caching?
|
389
385
|
|
390
|
-
fragments = resource_klass.
|
391
|
-
|
392
|
-
primary_resource_id_tree = PrimaryResourceIdTree.new
|
393
|
-
primary_resource_id_tree.add_resource_fragments(fragments, include_related)
|
394
|
-
|
395
|
-
load_included(resource_klass, primary_resource_id_tree, include_related, options)
|
396
|
-
|
397
|
-
primary_resource_id_tree
|
386
|
+
fragments = resource_klass.find_fragments(options[:filters], options)
|
387
|
+
PrimaryResourceTree.new(fragments: fragments, include_related: include_related, options: options)
|
398
388
|
end
|
399
389
|
|
400
|
-
def
|
401
|
-
options =
|
390
|
+
def find_related_resource_tree(parent_resource, relationship, options, include_related)
|
391
|
+
options = options.except(:include_directives)
|
402
392
|
options[:cache] = resource_klass.caching?
|
403
393
|
|
404
|
-
|
394
|
+
parent_resource_fragment = parent_resource.fragment(primary: true)
|
405
395
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
load_included(resource_klass, primary_resource_id_tree, include_related, options)
|
410
|
-
|
411
|
-
primary_resource_id_tree
|
396
|
+
fragments = resource_klass.find_related_fragments(parent_resource_fragment, relationship, options)
|
397
|
+
PrimaryResourceTree.new(fragments: fragments, include_related: include_related, options: options)
|
412
398
|
end
|
413
399
|
|
414
|
-
def
|
400
|
+
def find_resource_tree_from_relationship(resource, relationship_name, options, include_related)
|
415
401
|
relationship = resource.class._relationship(relationship_name)
|
416
402
|
|
417
|
-
options =
|
403
|
+
options = options.except(:include_directives)
|
418
404
|
options[:cache] = relationship.resource_klass.caching?
|
419
405
|
|
420
|
-
fragments = resource.class.find_related_fragments(
|
421
|
-
|
422
|
-
primary_resource_id_tree = PrimaryResourceIdTree.new
|
423
|
-
primary_resource_id_tree.add_resource_fragments(fragments, include_related)
|
424
|
-
|
425
|
-
load_included(resource_klass, primary_resource_id_tree, include_related, options)
|
406
|
+
fragments = resource.class.find_related_fragments(resource.fragment, relationship, options)
|
426
407
|
|
427
|
-
|
428
|
-
end
|
429
|
-
|
430
|
-
def load_included(resource_klass, source_resource_id_tree, include_related, options)
|
431
|
-
source_rids = source_resource_id_tree.fragments.keys
|
432
|
-
|
433
|
-
include_related.try(:each_key) do |key|
|
434
|
-
relationship = resource_klass._relationship(key)
|
435
|
-
relationship_name = relationship.name.to_sym
|
436
|
-
|
437
|
-
find_related_resource_options = options.except(:filters, :sort_criteria, :paginator)
|
438
|
-
find_related_resource_options[:sort_criteria] = relationship.resource_klass.default_sort
|
439
|
-
find_related_resource_options[:cache] = resource_klass.caching?
|
440
|
-
|
441
|
-
related_fragments = resource_klass.find_included_fragments(
|
442
|
-
source_rids, relationship_name, find_related_resource_options
|
443
|
-
)
|
444
|
-
|
445
|
-
related_resource_id_tree = source_resource_id_tree.fetch_related_resource_id_tree(relationship)
|
446
|
-
related_resource_id_tree.add_resource_fragments(related_fragments, include_related[key][include_related])
|
447
|
-
|
448
|
-
# Now recursively get the related resources for the currently found resources
|
449
|
-
load_included(relationship.resource_klass,
|
450
|
-
related_resource_id_tree,
|
451
|
-
include_related[relationship_name][:include_related],
|
452
|
-
options)
|
453
|
-
end
|
408
|
+
PrimaryResourceTree.new(fragments: fragments, include_related: include_related, options: options)
|
454
409
|
end
|
455
410
|
end
|
456
411
|
end
|
data/lib/jsonapi/relationship.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module JSONAPI
|
2
4
|
class Relationship
|
3
5
|
attr_reader :acts_as_set, :foreign_key, :options, :name,
|
4
|
-
:class_name, :polymorphic, :always_include_optional_linkage_data,
|
6
|
+
:class_name, :polymorphic, :always_include_optional_linkage_data, :exclude_linkage_data,
|
5
7
|
:parent_resource, :eager_load_on_include, :custom_methods,
|
6
|
-
:inverse_relationship, :allow_include, :use_related_resource_records_for_joins
|
8
|
+
:inverse_relationship, :allow_include, :hidden, :use_related_resource_records_for_joins
|
7
9
|
|
8
10
|
attr_writer :allow_include
|
9
11
|
|
@@ -15,7 +17,7 @@ module JSONAPI
|
|
15
17
|
@acts_as_set = options.fetch(:acts_as_set, false) == true
|
16
18
|
@foreign_key = options[:foreign_key] ? options[:foreign_key].to_sym : nil
|
17
19
|
@parent_resource = options[:parent_resource]
|
18
|
-
@relation_name = options
|
20
|
+
@relation_name = options[:relation_name]
|
19
21
|
@polymorphic = options.fetch(:polymorphic, false) == true
|
20
22
|
@polymorphic_types = options[:polymorphic_types]
|
21
23
|
if options[:polymorphic_relations]
|
@@ -28,15 +30,19 @@ module JSONAPI
|
|
28
30
|
else
|
29
31
|
JSONAPI.configuration.use_related_resource_records_for_joins
|
30
32
|
end
|
31
|
-
|
33
|
+
|
32
34
|
@use_related_resource_records_for_joins = options.fetch(:use_related_resource_records_for_joins,
|
33
35
|
use_related_resource_records_for_joins_default) == true
|
34
36
|
|
37
|
+
@hidden = options.fetch(:hidden, false) == true
|
38
|
+
|
39
|
+
@exclude_linkage_data = options[:exclude_linkage_data]
|
35
40
|
@always_include_optional_linkage_data = options.fetch(:always_include_optional_linkage_data, false) == true
|
36
|
-
@eager_load_on_include = options.fetch(:eager_load_on_include,
|
41
|
+
@eager_load_on_include = options.fetch(:eager_load_on_include, true) == true
|
37
42
|
@allow_include = options[:allow_include]
|
38
43
|
@class_name = nil
|
39
|
-
|
44
|
+
|
45
|
+
@inverse_relationship = options[:inverse_relationship]&.to_sym
|
40
46
|
|
41
47
|
@_routed = false
|
42
48
|
@_warned_missing_route = false
|
@@ -66,12 +72,26 @@ module JSONAPI
|
|
66
72
|
# :nocov:
|
67
73
|
end
|
68
74
|
|
75
|
+
def inverse_relationship
|
76
|
+
unless @inverse_relationship
|
77
|
+
@inverse_relationship ||= if resource_klass._relationship(@parent_resource._type.to_s.singularize).present?
|
78
|
+
@parent_resource._type.to_s.singularize.to_sym
|
79
|
+
elsif resource_klass._relationship(@parent_resource._type).present?
|
80
|
+
@parent_resource._type.to_sym
|
81
|
+
else
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
@inverse_relationship
|
87
|
+
end
|
88
|
+
|
69
89
|
def self.polymorphic_types(name)
|
70
90
|
@poly_hash ||= {}.tap do |hash|
|
71
91
|
ObjectSpace.each_object do |klass|
|
72
92
|
next unless Module === klass
|
73
93
|
if ActiveRecord::Base > klass
|
74
|
-
klass.reflect_on_all_associations(:has_many).select{|r| r.options[:as] }.each do |reflection|
|
94
|
+
klass.reflect_on_all_associations(:has_many).select { |r| r.options[:as] }.each do |reflection|
|
75
95
|
(hash[reflection.options[:as]] ||= []) << klass.name.underscore
|
76
96
|
end
|
77
97
|
end
|
@@ -82,7 +102,7 @@ module JSONAPI
|
|
82
102
|
|
83
103
|
def resource_types
|
84
104
|
if polymorphic? && belongs_to?
|
85
|
-
@polymorphic_types ||= self.class.polymorphic_types(
|
105
|
+
@polymorphic_types ||= self.class.polymorphic_types(_relation_name).collect { |t| t.pluralize }
|
86
106
|
else
|
87
107
|
[resource_klass._type.to_s.pluralize]
|
88
108
|
end
|
@@ -93,15 +113,15 @@ module JSONAPI
|
|
93
113
|
end
|
94
114
|
|
95
115
|
def relation_name(options)
|
96
|
-
case
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
116
|
+
case _relation_name
|
117
|
+
when Symbol
|
118
|
+
# :nocov:
|
119
|
+
_relation_name
|
120
|
+
# :nocov:
|
121
|
+
when String
|
122
|
+
_relation_name.to_sym
|
123
|
+
when Proc
|
124
|
+
_relation_name.call(options)
|
105
125
|
end
|
106
126
|
end
|
107
127
|
|
@@ -117,14 +137,14 @@ module JSONAPI
|
|
117
137
|
|
118
138
|
def exclude_links(exclude)
|
119
139
|
case exclude
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
140
|
+
when :default, "default"
|
141
|
+
@_exclude_links = [:self, :related]
|
142
|
+
when :none, "none"
|
143
|
+
@_exclude_links = []
|
144
|
+
when Array
|
145
|
+
@_exclude_links = exclude.collect { |link| link.to_sym }
|
146
|
+
else
|
147
|
+
fail "Invalid exclude_links"
|
128
148
|
end
|
129
149
|
end
|
130
150
|
|
@@ -136,6 +156,10 @@ module JSONAPI
|
|
136
156
|
_exclude_links.include?(link.to_sym)
|
137
157
|
end
|
138
158
|
|
159
|
+
def _relation_name
|
160
|
+
@relation_name || @name
|
161
|
+
end
|
162
|
+
|
139
163
|
class ToOne < Relationship
|
140
164
|
attr_reader :foreign_key_on
|
141
165
|
|
@@ -144,9 +168,16 @@ module JSONAPI
|
|
144
168
|
@class_name = options.fetch(:class_name, name.to_s.camelize)
|
145
169
|
@foreign_key ||= "#{name}_id".to_sym
|
146
170
|
@foreign_key_on = options.fetch(:foreign_key_on, :self)
|
147
|
-
if parent_resource
|
148
|
-
|
171
|
+
# if parent_resource
|
172
|
+
# @inverse_relationship = options.fetch(:inverse_relationship, parent_resource._type)
|
173
|
+
# end
|
174
|
+
|
175
|
+
if options.fetch(:create_implicit_polymorphic_type_relationships, true) == true && polymorphic?
|
176
|
+
# Setup the implicit relationships for the polymorphic types and exclude linkage data
|
177
|
+
setup_implicit_relationships_for_polymorphic_types
|
149
178
|
end
|
179
|
+
|
180
|
+
@polymorphic_type_relationship_for = options[:polymorphic_type_relationship_for]
|
150
181
|
end
|
151
182
|
|
152
183
|
def to_s
|
@@ -161,11 +192,30 @@ module JSONAPI
|
|
161
192
|
# :nocov:
|
162
193
|
end
|
163
194
|
|
195
|
+
def hidden?
|
196
|
+
@hidden || @polymorphic_type_relationship_for.present?
|
197
|
+
end
|
198
|
+
|
164
199
|
def polymorphic_type
|
165
200
|
"#{name}_type" if polymorphic?
|
166
201
|
end
|
167
202
|
|
203
|
+
def setup_implicit_relationships_for_polymorphic_types(exclude_linkage_data: true)
|
204
|
+
types = self.class.polymorphic_types(_relation_name)
|
205
|
+
unless types.present?
|
206
|
+
warn "No polymorphic types found for #{parent_resource.name} #{_relation_name}"
|
207
|
+
return
|
208
|
+
end
|
209
|
+
|
210
|
+
types.each do |type|
|
211
|
+
parent_resource.has_one(type.to_s.underscore.singularize,
|
212
|
+
exclude_linkage_data: exclude_linkage_data,
|
213
|
+
polymorphic_type_relationship_for: name)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
168
217
|
def include_optional_linkage_data?
|
218
|
+
return false if @exclude_linkage_data
|
169
219
|
@always_include_optional_linkage_data || JSONAPI::configuration.always_include_to_one_linkage_data
|
170
220
|
end
|
171
221
|
|
@@ -176,10 +226,10 @@ module JSONAPI
|
|
176
226
|
@allow_include
|
177
227
|
end
|
178
228
|
|
179
|
-
if !!strategy == strategy #check for boolean
|
229
|
+
if !!strategy == strategy # check for boolean
|
180
230
|
return strategy
|
181
231
|
elsif strategy.is_a?(Symbol) || strategy.is_a?(String)
|
182
|
-
|
232
|
+
parent_resource_klass.send(strategy, context)
|
183
233
|
else
|
184
234
|
strategy.call(context)
|
185
235
|
end
|
@@ -194,17 +244,21 @@ module JSONAPI
|
|
194
244
|
@class_name = options.fetch(:class_name, name.to_s.camelize.singularize)
|
195
245
|
@foreign_key ||= "#{name.to_s.singularize}_ids".to_sym
|
196
246
|
@reflect = options.fetch(:reflect, true) == true
|
197
|
-
if parent_resource
|
198
|
-
|
199
|
-
end
|
247
|
+
# if parent_resource
|
248
|
+
# @inverse_relationship = options.fetch(:inverse_relationship, parent_resource._type.to_s.singularize.to_sym)
|
249
|
+
# end
|
200
250
|
end
|
201
251
|
|
202
252
|
def to_s
|
203
253
|
# :nocov: useful for debugging
|
204
|
-
"#{
|
254
|
+
"#{parent_resource_klass}.#{name}(ToMany)"
|
205
255
|
# :nocov:
|
206
256
|
end
|
207
257
|
|
258
|
+
def hidden?
|
259
|
+
@hidden
|
260
|
+
end
|
261
|
+
|
208
262
|
def include_optional_linkage_data?
|
209
263
|
# :nocov:
|
210
264
|
@always_include_optional_linkage_data || JSONAPI::configuration.always_include_to_many_linkage_data
|
@@ -218,10 +272,10 @@ module JSONAPI
|
|
218
272
|
@allow_include
|
219
273
|
end
|
220
274
|
|
221
|
-
if !!strategy == strategy #check for boolean
|
275
|
+
if !!strategy == strategy # check for boolean
|
222
276
|
return strategy
|
223
277
|
elsif strategy.is_a?(Symbol) || strategy.is_a?(String)
|
224
|
-
|
278
|
+
parent_resource_klass.send(strategy, context)
|
225
279
|
else
|
226
280
|
strategy.call(context)
|
227
281
|
end
|