jsonapi-resources 0.10.0.beta3 → 0.10.0.beta4
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/lib/jsonapi-resources.rb +4 -2
- data/lib/jsonapi/{active_relation_resource_finder → active_relation}/adapters/join_left_active_record_adapter.rb +1 -1
- data/lib/jsonapi/{active_relation_resource_finder → active_relation}/join_manager.rb +1 -1
- data/lib/jsonapi/{active_relation_resource_finder.rb → active_relation_resource.rb} +96 -44
- data/lib/jsonapi/acts_as_resource_controller.rb +1 -1
- data/lib/jsonapi/basic_resource.rb +1137 -0
- data/lib/jsonapi/configuration.rb +4 -12
- data/lib/jsonapi/include_directives.rb +6 -8
- data/lib/jsonapi/link_builder.rb +100 -77
- data/lib/jsonapi/operation_result.rb +2 -2
- data/lib/jsonapi/processor.rb +6 -7
- data/lib/jsonapi/relationship.rb +26 -3
- data/lib/jsonapi/request_parser.rb +44 -10
- data/lib/jsonapi/resource.rb +3 -1106
- data/lib/jsonapi/resource_serializer.rb +35 -31
- data/lib/jsonapi/resource_set.rb +1 -1
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/response_document.rb +7 -2
- data/lib/jsonapi/routing_ext.rb +16 -4
- metadata +22 -6
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'jsonapi/formatter'
|
2
2
|
require 'jsonapi/processor'
|
3
|
-
require 'jsonapi/active_relation_resource_finder'
|
4
3
|
require 'concurrent'
|
5
4
|
|
6
5
|
module JSONAPI
|
@@ -10,6 +9,7 @@ module JSONAPI
|
|
10
9
|
:route_format,
|
11
10
|
:raise_if_parameters_not_allowed,
|
12
11
|
:warn_on_route_setup_issues,
|
12
|
+
:warn_on_missing_routes,
|
13
13
|
:default_allow_include_to_one,
|
14
14
|
:default_allow_include_to_many,
|
15
15
|
:allow_sort,
|
@@ -17,7 +17,6 @@ module JSONAPI
|
|
17
17
|
:default_paginator,
|
18
18
|
:default_page_size,
|
19
19
|
:maximum_page_size,
|
20
|
-
:resource_finder,
|
21
20
|
:default_processor_klass,
|
22
21
|
:use_text_errors,
|
23
22
|
:top_level_links_include_pagination,
|
@@ -59,6 +58,7 @@ module JSONAPI
|
|
59
58
|
self.raise_if_parameters_not_allowed = true
|
60
59
|
|
61
60
|
self.warn_on_route_setup_issues = true
|
61
|
+
self.warn_on_missing_routes = true
|
62
62
|
|
63
63
|
# :none, :offset, :paged, or a custom paginator name
|
64
64
|
self.default_paginator = :none
|
@@ -105,12 +105,6 @@ module JSONAPI
|
|
105
105
|
self.always_include_to_one_linkage_data = false
|
106
106
|
self.always_include_to_many_linkage_data = false
|
107
107
|
|
108
|
-
# ResourceFinder Mixin
|
109
|
-
# The default ResourceFinder is the ActiveRelationResourceFinder which provides
|
110
|
-
# access to ActiveRelation backed models. Custom ResourceFinders can be specified
|
111
|
-
# in order to support other ORMs.
|
112
|
-
self.resource_finder = JSONAPI::ActiveRelationResourceFinder
|
113
|
-
|
114
108
|
# The default Operation Processor to use if one is not defined specifically
|
115
109
|
# for a Resource.
|
116
110
|
self.default_processor_klass = JSONAPI::Processor
|
@@ -225,10 +219,6 @@ module JSONAPI
|
|
225
219
|
@default_processor_klass = default_processor_klass
|
226
220
|
end
|
227
221
|
|
228
|
-
def resource_finder=(resource_finder)
|
229
|
-
@resource_finder = resource_finder
|
230
|
-
end
|
231
|
-
|
232
222
|
def allow_include=(allow_include)
|
233
223
|
ActiveSupport::Deprecation.warn('`allow_include` has been replaced by `default_allow_include_to_one` and `default_allow_include_to_many` options.')
|
234
224
|
@default_allow_include_to_one = allow_include
|
@@ -273,6 +263,8 @@ module JSONAPI
|
|
273
263
|
|
274
264
|
attr_writer :warn_on_route_setup_issues
|
275
265
|
|
266
|
+
attr_writer :warn_on_missing_routes
|
267
|
+
|
276
268
|
attr_writer :use_relationship_reflection
|
277
269
|
|
278
270
|
attr_writer :resource_cache
|
@@ -4,14 +4,12 @@ module JSONAPI
|
|
4
4
|
# For example ['posts.comments.tags']
|
5
5
|
# will transform into =>
|
6
6
|
# {
|
7
|
-
# posts:{
|
8
|
-
#
|
9
|
-
# include_related:{
|
7
|
+
# posts: {
|
8
|
+
# include_related: {
|
10
9
|
# comments:{
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
# include:true
|
10
|
+
# include_related: {
|
11
|
+
# tags: {
|
12
|
+
# include_related: {}
|
15
13
|
# }
|
16
14
|
# }
|
17
15
|
# }
|
@@ -44,7 +42,7 @@ module JSONAPI
|
|
44
42
|
path.segments.each do |segment|
|
45
43
|
relationship_name = segment.relationship.name.to_sym
|
46
44
|
|
47
|
-
current[:include_related][relationship_name] ||= {
|
45
|
+
current[:include_related][relationship_name] ||= { include_related: {} }
|
48
46
|
current = current[:include_related][relationship_name]
|
49
47
|
end
|
50
48
|
|
data/lib/jsonapi/link_builder.rb
CHANGED
@@ -2,32 +2,33 @@ module JSONAPI
|
|
2
2
|
class LinkBuilder
|
3
3
|
attr_reader :base_url,
|
4
4
|
:primary_resource_klass,
|
5
|
-
:
|
6
|
-
:
|
5
|
+
:engine,
|
6
|
+
:routes
|
7
7
|
|
8
8
|
def initialize(config = {})
|
9
9
|
@base_url = config[:base_url]
|
10
10
|
@primary_resource_klass = config[:primary_resource_klass]
|
11
|
-
@
|
12
|
-
@engine_name = build_engine_name
|
11
|
+
@engine = build_engine
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
13
|
+
if engine?
|
14
|
+
@routes = @engine.routes
|
15
|
+
else
|
16
|
+
@routes = Rails.application.routes
|
18
17
|
end
|
18
|
+
|
19
|
+
# ToDo: Use NaiveCache for values. For this we need to not return nils and create composite keys which work
|
20
|
+
# as efficient cache lookups. This could be an array of the [source.identifier, relationship] since the
|
21
|
+
# ResourceIdentity will compare equality correctly
|
19
22
|
end
|
20
23
|
|
21
24
|
def engine?
|
22
|
-
!!@
|
25
|
+
!!@engine
|
23
26
|
end
|
24
27
|
|
25
28
|
def primary_resources_url
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
regular_primary_resources_url
|
30
|
-
end
|
29
|
+
@primary_resources_url_cached ||= "#{ base_url }#{ primary_resources_path }"
|
30
|
+
rescue NoMethodError
|
31
|
+
warn "primary_resources_url for #{@primary_resource_klass} could not be generated" if JSONAPI.configuration.warn_on_missing_routes
|
31
32
|
end
|
32
33
|
|
33
34
|
def query_link(query_params)
|
@@ -35,26 +36,45 @@ module JSONAPI
|
|
35
36
|
end
|
36
37
|
|
37
38
|
def relationships_related_link(source, relationship, query_params = {})
|
38
|
-
|
39
|
+
if relationship.parent_resource.singleton?
|
40
|
+
url_helper_name = singleton_related_url_helper_name(relationship)
|
41
|
+
url = call_url_helper(url_helper_name)
|
42
|
+
else
|
43
|
+
url_helper_name = related_url_helper_name(relationship)
|
44
|
+
url = call_url_helper(url_helper_name, source.id)
|
45
|
+
end
|
46
|
+
|
47
|
+
url = "#{ base_url }#{ url }"
|
39
48
|
url = "#{ url }?#{ query_params.to_query }" if query_params.present?
|
40
49
|
url
|
50
|
+
rescue NoMethodError
|
51
|
+
warn "related_link for #{relationship} could not be generated" if JSONAPI.configuration.warn_on_missing_routes
|
41
52
|
end
|
42
53
|
|
43
54
|
def relationships_self_link(source, relationship)
|
44
|
-
|
55
|
+
if relationship.parent_resource.singleton?
|
56
|
+
url_helper_name = singleton_relationship_self_url_helper_name(relationship)
|
57
|
+
url = call_url_helper(url_helper_name)
|
58
|
+
else
|
59
|
+
url_helper_name = relationship_self_url_helper_name(relationship)
|
60
|
+
url = call_url_helper(url_helper_name, source.id)
|
61
|
+
end
|
62
|
+
|
63
|
+
url = "#{ base_url }#{ url }"
|
64
|
+
url
|
65
|
+
rescue NoMethodError
|
66
|
+
warn "self_link for #{relationship} could not be generated" if JSONAPI.configuration.warn_on_missing_routes
|
45
67
|
end
|
46
68
|
|
47
69
|
def self_link(source)
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
regular_resource_url(source)
|
52
|
-
end
|
70
|
+
"#{ base_url }#{ resource_path(source) }"
|
71
|
+
rescue NoMethodError
|
72
|
+
warn "self_link for #{source.class} could not be generated" if JSONAPI.configuration.warn_on_missing_routes
|
53
73
|
end
|
54
74
|
|
55
75
|
private
|
56
76
|
|
57
|
-
def
|
77
|
+
def build_engine
|
58
78
|
scopes = module_scopes_from_class(primary_resource_klass)
|
59
79
|
|
60
80
|
begin
|
@@ -68,93 +88,96 @@ module JSONAPI
|
|
68
88
|
end
|
69
89
|
end
|
70
90
|
|
71
|
-
def
|
72
|
-
|
73
|
-
|
91
|
+
def call_url_helper(method, *args)
|
92
|
+
routes.url_helpers.public_send(method, args)
|
93
|
+
rescue NoMethodError => e
|
94
|
+
raise e
|
74
95
|
end
|
75
96
|
|
76
|
-
def
|
77
|
-
|
97
|
+
def path_from_resource_class(klass)
|
98
|
+
url_helper_name = resources_url_helper_name_from_class(klass)
|
99
|
+
call_url_helper(url_helper_name)
|
78
100
|
end
|
79
101
|
|
80
|
-
def
|
81
|
-
|
102
|
+
def resource_path(source)
|
103
|
+
url_helper_name = resource_url_helper_name_from_source(source)
|
104
|
+
if source.class.singleton?
|
105
|
+
call_url_helper(url_helper_name)
|
106
|
+
else
|
107
|
+
call_url_helper(url_helper_name, source.id)
|
108
|
+
end
|
82
109
|
end
|
83
110
|
|
84
|
-
def
|
85
|
-
|
86
|
-
engine_name.routes.url_helpers.public_send(resource_path_name, source.id)
|
111
|
+
def primary_resources_path
|
112
|
+
path_from_resource_class(primary_resource_klass)
|
87
113
|
end
|
88
114
|
|
89
|
-
def
|
90
|
-
|
91
|
-
base_path_name = scopes.map { |scope| scope.underscore }.join("_")
|
92
|
-
end_path_name = source.class._type.to_s.singularize
|
93
|
-
[base_path_name, end_path_name, "path"].reject(&:blank?).join("_")
|
115
|
+
def url_helper_name_from_parts(parts)
|
116
|
+
(parts << "path").reject(&:blank?).join("_")
|
94
117
|
end
|
95
118
|
|
96
|
-
def
|
97
|
-
|
98
|
-
|
119
|
+
def resources_path_parts_from_class(klass)
|
120
|
+
if engine?
|
121
|
+
scopes = module_scopes_from_class(klass)[1..-1]
|
122
|
+
else
|
123
|
+
scopes = module_scopes_from_class(klass)
|
124
|
+
end
|
99
125
|
|
100
|
-
def engine_resources_path_name_from_class(klass)
|
101
|
-
scopes = module_scopes_from_class(klass)[1..-1]
|
102
126
|
base_path_name = scopes.map { |scope| scope.underscore }.join("_")
|
103
127
|
end_path_name = klass._type.to_s
|
104
|
-
|
105
|
-
if base_path_name.blank?
|
106
|
-
"#{ end_path_name }_path"
|
107
|
-
else
|
108
|
-
"#{ base_path_name }_#{ end_path_name }_path"
|
109
|
-
end
|
128
|
+
[base_path_name, end_path_name]
|
110
129
|
end
|
111
130
|
|
112
|
-
def
|
113
|
-
|
131
|
+
def resources_url_helper_name_from_class(klass)
|
132
|
+
url_helper_name_from_parts(resources_path_parts_from_class(klass))
|
114
133
|
end
|
115
134
|
|
116
|
-
def
|
117
|
-
|
118
|
-
|
119
|
-
unless scopes.empty?
|
120
|
-
"/#{ scopes.map{ |scope| format_route(scope.to_s.underscore) }.compact.join('/') }/"
|
135
|
+
def resource_path_parts_from_class(klass)
|
136
|
+
if engine?
|
137
|
+
scopes = module_scopes_from_class(klass)[1..-1]
|
121
138
|
else
|
122
|
-
|
139
|
+
scopes = module_scopes_from_class(klass)
|
123
140
|
end
|
124
|
-
end
|
125
141
|
|
126
|
-
|
127
|
-
klass.
|
142
|
+
base_path_name = scopes.map { |scope| scope.underscore }.join("_")
|
143
|
+
end_path_name = klass._type.to_s.singularize
|
144
|
+
[base_path_name, end_path_name]
|
128
145
|
end
|
129
146
|
|
130
|
-
def
|
131
|
-
|
147
|
+
def resource_url_helper_name_from_source(source)
|
148
|
+
url_helper_name_from_parts(resource_path_parts_from_class(source.class))
|
132
149
|
end
|
133
150
|
|
134
|
-
def
|
135
|
-
|
151
|
+
def related_url_helper_name(relationship)
|
152
|
+
relationship_parts = resource_path_parts_from_class(relationship.parent_resource)
|
153
|
+
relationship_parts << relationship.name
|
154
|
+
url_helper_name_from_parts(relationship_parts)
|
136
155
|
end
|
137
156
|
|
138
|
-
def
|
139
|
-
|
157
|
+
def singleton_related_url_helper_name(relationship)
|
158
|
+
relationship_parts = []
|
159
|
+
relationship_parts << relationship.name
|
160
|
+
relationship_parts += resource_path_parts_from_class(relationship.parent_resource)
|
161
|
+
url_helper_name_from_parts(relationship_parts)
|
140
162
|
end
|
141
163
|
|
142
|
-
def
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
else
|
148
|
-
"#{regular_resources_path(source.class)}/#{source.id}"
|
149
|
-
end
|
164
|
+
def relationship_self_url_helper_name(relationship)
|
165
|
+
relationship_parts = resource_path_parts_from_class(relationship.parent_resource)
|
166
|
+
relationship_parts << "relationships"
|
167
|
+
relationship_parts << relationship.name
|
168
|
+
url_helper_name_from_parts(relationship_parts)
|
150
169
|
end
|
151
170
|
|
152
|
-
def
|
153
|
-
|
171
|
+
def singleton_relationship_self_url_helper_name(relationship)
|
172
|
+
relationship_parts = []
|
173
|
+
relationship_parts << "relationships"
|
174
|
+
relationship_parts << relationship.name
|
175
|
+
relationship_parts += resource_path_parts_from_class(relationship.parent_resource)
|
176
|
+
url_helper_name_from_parts(relationship_parts)
|
154
177
|
end
|
155
178
|
|
156
|
-
def
|
157
|
-
|
179
|
+
def module_scopes_from_class(klass)
|
180
|
+
klass.name.to_s.split("::")[0...-1]
|
158
181
|
end
|
159
182
|
end
|
160
183
|
end
|
@@ -100,7 +100,7 @@ module JSONAPI
|
|
100
100
|
end
|
101
101
|
end
|
102
102
|
|
103
|
-
class
|
103
|
+
class RelationshipOperationResult < OperationResult
|
104
104
|
attr_accessor :parent_resource, :relationship, :resource_ids
|
105
105
|
|
106
106
|
def initialize(code, parent_resource, relationship, resource_ids, options = {})
|
@@ -112,7 +112,7 @@ module JSONAPI
|
|
112
112
|
|
113
113
|
def to_hash(serializer = nil)
|
114
114
|
if serializer
|
115
|
-
serializer.
|
115
|
+
serializer.serialize_to_relationship_hash(parent_resource, relationship, resource_ids)
|
116
116
|
else
|
117
117
|
# :nocov:
|
118
118
|
{}
|
data/lib/jsonapi/processor.rb
CHANGED
@@ -130,11 +130,11 @@ module JSONAPI
|
|
130
130
|
find_options,
|
131
131
|
nil)
|
132
132
|
|
133
|
-
return JSONAPI::
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
133
|
+
return JSONAPI::RelationshipOperationResult.new(:ok,
|
134
|
+
parent_resource,
|
135
|
+
resource_klass._relationship(relationship_type),
|
136
|
+
resource_id_tree.fragments.keys,
|
137
|
+
result_options)
|
138
138
|
end
|
139
139
|
|
140
140
|
def show_related_resource
|
@@ -429,8 +429,7 @@ module JSONAPI
|
|
429
429
|
def load_included(resource_klass, source_resource_id_tree, include_related, options)
|
430
430
|
source_rids = source_resource_id_tree.fragments.keys
|
431
431
|
|
432
|
-
include_related.try(:
|
433
|
-
next unless value[:include]
|
432
|
+
include_related.try(:each_key) do |key|
|
434
433
|
relationship = resource_klass._relationship(key)
|
435
434
|
relationship_name = relationship.name.to_sym
|
436
435
|
|
data/lib/jsonapi/relationship.rb
CHANGED
@@ -27,7 +27,9 @@ module JSONAPI
|
|
27
27
|
@class_name = nil
|
28
28
|
@inverse_relationship = nil
|
29
29
|
|
30
|
-
|
30
|
+
exclude_links(options.fetch(:exclude_links, :none))
|
31
|
+
|
32
|
+
# Custom methods are reserved for future use
|
31
33
|
@custom_methods = options.fetch(:custom_methods, {})
|
32
34
|
end
|
33
35
|
|
@@ -99,6 +101,27 @@ module JSONAPI
|
|
99
101
|
@options[:readonly]
|
100
102
|
end
|
101
103
|
|
104
|
+
def exclude_links(exclude)
|
105
|
+
case exclude
|
106
|
+
when :default, "default"
|
107
|
+
@_exclude_links = [:self, :related]
|
108
|
+
when :none, "none"
|
109
|
+
@_exclude_links = []
|
110
|
+
when Array
|
111
|
+
@_exclude_links = exclude.collect {|link| link.to_sym}
|
112
|
+
else
|
113
|
+
fail "Invalid exclude_links"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def _exclude_links
|
118
|
+
@_exclude_links ||= []
|
119
|
+
end
|
120
|
+
|
121
|
+
def exclude_link?(link)
|
122
|
+
_exclude_links.include?(link.to_sym)
|
123
|
+
end
|
124
|
+
|
102
125
|
class ToOne < Relationship
|
103
126
|
attr_reader :foreign_key_on
|
104
127
|
|
@@ -114,7 +137,7 @@ module JSONAPI
|
|
114
137
|
|
115
138
|
def to_s
|
116
139
|
# :nocov: useful for debugging
|
117
|
-
"#{parent_resource
|
140
|
+
"#{parent_resource}.#{name}(#{belongs_to? ? 'BelongsToOne' : 'ToOne'})"
|
118
141
|
# :nocov:
|
119
142
|
end
|
120
143
|
|
@@ -164,7 +187,7 @@ module JSONAPI
|
|
164
187
|
|
165
188
|
def to_s
|
166
189
|
# :nocov: useful for debugging
|
167
|
-
"#{parent_resource
|
190
|
+
"#{parent_resource}.#{name}(ToMany)"
|
168
191
|
# :nocov:
|
169
192
|
end
|
170
193
|
|
@@ -81,6 +81,7 @@ module JSONAPI
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def setup_show_related_resource_action(params, resource_klass)
|
84
|
+
resolve_singleton_id(params, resource_klass)
|
84
85
|
source_klass = Resource.resource_klass_for(params.require(:source))
|
85
86
|
source_id = source_klass.verify_key(params.require(source_klass._as_parent_key), @context)
|
86
87
|
|
@@ -102,6 +103,7 @@ module JSONAPI
|
|
102
103
|
end
|
103
104
|
|
104
105
|
def setup_index_related_resources_action(params, resource_klass)
|
106
|
+
resolve_singleton_id(params, resource_klass)
|
105
107
|
source_klass = Resource.resource_klass_for(params.require(:source))
|
106
108
|
source_id = source_klass.verify_key(params.require(source_klass._as_parent_key), @context)
|
107
109
|
|
@@ -128,6 +130,7 @@ module JSONAPI
|
|
128
130
|
end
|
129
131
|
|
130
132
|
def setup_show_action(params, resource_klass)
|
133
|
+
resolve_singleton_id(params, resource_klass)
|
131
134
|
fields = parse_fields(resource_klass, params[:fields])
|
132
135
|
include_directives = parse_include_directives(resource_klass, params[:include])
|
133
136
|
id = params[:id]
|
@@ -144,6 +147,7 @@ module JSONAPI
|
|
144
147
|
end
|
145
148
|
|
146
149
|
def setup_show_relationship_action(params, resource_klass)
|
150
|
+
resolve_singleton_id(params, resource_klass)
|
147
151
|
relationship_type = params[:relationship]
|
148
152
|
parent_key = params.require(resource_klass._as_parent_key)
|
149
153
|
include_directives = parse_include_directives(resource_klass, params[:include])
|
@@ -191,6 +195,7 @@ module JSONAPI
|
|
191
195
|
end
|
192
196
|
|
193
197
|
def setup_create_relationship_action(params, resource_klass)
|
198
|
+
resolve_singleton_id(params, resource_klass)
|
194
199
|
parse_modify_relationship_action(:add, params, resource_klass)
|
195
200
|
end
|
196
201
|
|
@@ -199,6 +204,7 @@ module JSONAPI
|
|
199
204
|
end
|
200
205
|
|
201
206
|
def setup_update_action(params, resource_klass)
|
207
|
+
resolve_singleton_id(params, resource_klass)
|
202
208
|
fields = parse_fields(resource_klass, params[:fields])
|
203
209
|
include_directives = parse_include_directives(resource_klass, params[:include])
|
204
210
|
|
@@ -232,6 +238,7 @@ module JSONAPI
|
|
232
238
|
end
|
233
239
|
|
234
240
|
def setup_destroy_action(params, resource_klass)
|
241
|
+
resolve_singleton_id(params, resource_klass)
|
235
242
|
JSONAPI::Operation.new(
|
236
243
|
:remove_resource,
|
237
244
|
resource_klass,
|
@@ -240,6 +247,7 @@ module JSONAPI
|
|
240
247
|
end
|
241
248
|
|
242
249
|
def setup_destroy_relationship_action(params, resource_klass)
|
250
|
+
resolve_singleton_id(params, resource_klass)
|
243
251
|
parse_modify_relationship_action(:remove, params, resource_klass)
|
244
252
|
end
|
245
253
|
|
@@ -556,20 +564,39 @@ module JSONAPI
|
|
556
564
|
|
557
565
|
links_object = parse_to_many_links_object(linkage)
|
558
566
|
|
559
|
-
# Since we do not yet support polymorphic to_many relationships we will raise an error if the type does not match the
|
560
|
-
# relationship's type.
|
561
|
-
# ToDo: Support Polymorphic relationships
|
562
|
-
|
563
567
|
if links_object.length == 0
|
564
568
|
add_result.call([])
|
565
569
|
else
|
566
|
-
if
|
567
|
-
|
568
|
-
|
570
|
+
if relationship.polymorphic?
|
571
|
+
polymorphic_results = []
|
572
|
+
|
573
|
+
links_object.each_pair do |type, keys|
|
574
|
+
type_name = unformat_key(type).to_s
|
575
|
+
|
576
|
+
relationship_resource_klass = resource_klass.resource_klass_for(relationship.class_name)
|
577
|
+
relationship_klass = relationship_resource_klass._model_class
|
569
578
|
|
570
|
-
|
571
|
-
|
572
|
-
|
579
|
+
linkage_object_resource_klass = resource_klass.resource_klass_for(type_name)
|
580
|
+
linkage_object_klass = linkage_object_resource_klass._model_class
|
581
|
+
|
582
|
+
unless linkage_object_klass == relationship_klass || linkage_object_klass.in?(relationship_klass.subclasses)
|
583
|
+
fail JSONAPI::Exceptions::TypeMismatch.new(type_name)
|
584
|
+
end
|
585
|
+
|
586
|
+
relationship_ids = relationship_resource_klass.verify_keys(keys, @context)
|
587
|
+
polymorphic_results << { type: type, ids: relationship_ids }
|
588
|
+
end
|
589
|
+
|
590
|
+
add_result.call polymorphic_results
|
591
|
+
else
|
592
|
+
relationship_type = unformat_key(relationship.type).to_s
|
593
|
+
|
594
|
+
if links_object.length > 1 || !links_object.has_key?(relationship_type)
|
595
|
+
fail JSONAPI::Exceptions::TypeMismatch.new(links_object[:type])
|
596
|
+
end
|
597
|
+
|
598
|
+
relationship_resource_klass = Resource.resource_klass_for(resource_klass.module_path + relationship_type)
|
599
|
+
add_result.call relationship_resource_klass.verify_keys(links_object[relationship_type], @context)
|
573
600
|
end
|
574
601
|
end
|
575
602
|
end
|
@@ -695,6 +722,13 @@ module JSONAPI
|
|
695
722
|
end
|
696
723
|
end
|
697
724
|
|
725
|
+
def resolve_singleton_id(params, resource_klass)
|
726
|
+
if resource_klass.singleton? && params[:id].nil?
|
727
|
+
key = resource_klass.singleton_key(context)
|
728
|
+
params[:id] = key
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
698
732
|
def format_key(key)
|
699
733
|
@key_formatter.format(key)
|
700
734
|
end
|