jsonapi-resources 0.9.3 → 0.10.5
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 +5 -5
- data/LICENSE.txt +1 -1
- data/README.md +34 -11
- data/lib/bug_report_templates/rails_5_latest.rb +125 -0
- data/lib/bug_report_templates/rails_5_master.rb +140 -0
- data/lib/jsonapi/active_relation/adapters/join_left_active_record_adapter.rb +27 -0
- data/lib/jsonapi/active_relation/join_manager.rb +297 -0
- data/lib/jsonapi/active_relation_resource.rb +879 -0
- data/lib/jsonapi/acts_as_resource_controller.rb +122 -105
- data/lib/jsonapi/basic_resource.rb +1162 -0
- data/lib/jsonapi/cached_response_fragment.rb +127 -0
- data/lib/jsonapi/compiled_json.rb +11 -1
- data/lib/jsonapi/configuration.rb +63 -8
- data/lib/jsonapi/error.rb +27 -0
- data/lib/jsonapi/error_codes.rb +2 -0
- data/lib/jsonapi/exceptions.rb +63 -40
- data/lib/jsonapi/formatter.rb +3 -3
- data/lib/jsonapi/include_directives.rb +18 -65
- data/lib/jsonapi/link_builder.rb +74 -80
- data/lib/jsonapi/operation.rb +16 -5
- data/lib/jsonapi/operation_result.rb +74 -16
- data/lib/jsonapi/path.rb +43 -0
- data/lib/jsonapi/path_segment.rb +76 -0
- data/lib/jsonapi/processor.rb +237 -110
- data/lib/jsonapi/relationship.rb +144 -15
- data/lib/jsonapi/request_parser.rb +412 -357
- data/lib/jsonapi/resource.rb +3 -1263
- data/lib/jsonapi/resource_controller_metal.rb +5 -2
- data/lib/jsonapi/resource_fragment.rb +47 -0
- data/lib/jsonapi/resource_id_tree.rb +112 -0
- data/lib/jsonapi/resource_identity.rb +42 -0
- data/lib/jsonapi/resource_serializer.rb +143 -285
- data/lib/jsonapi/resource_set.rb +176 -0
- data/lib/jsonapi/resources/railtie.rb +9 -0
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/response_document.rb +105 -83
- data/lib/jsonapi/routing_ext.rb +48 -26
- data/lib/jsonapi-resources.rb +20 -4
- data/lib/tasks/check_upgrade.rake +52 -0
- metadata +47 -17
- data/lib/jsonapi/cached_resource_fragment.rb +0 -127
- data/lib/jsonapi/operation_dispatcher.rb +0 -88
- data/lib/jsonapi/operation_results.rb +0 -35
- data/lib/jsonapi/relationship_builder.rb +0 -167
@@ -1,121 +1,261 @@
|
|
1
|
-
require 'jsonapi/operation'
|
2
|
-
require 'jsonapi/paginator'
|
3
|
-
|
4
1
|
module JSONAPI
|
5
2
|
class RequestParser
|
6
|
-
attr_accessor :fields, :include, :filters, :sort_criteria, :errors, :
|
7
|
-
:
|
3
|
+
attr_accessor :fields, :include, :filters, :sort_criteria, :errors, :controller_module_path,
|
4
|
+
:context, :paginator, :source_klass, :source_id,
|
8
5
|
:include_directives, :params, :warnings, :server_error_callbacks
|
9
6
|
|
10
7
|
def initialize(params = nil, options = {})
|
11
8
|
@params = params
|
9
|
+
if params
|
10
|
+
controller_path = params.fetch(:controller, '')
|
11
|
+
@controller_module_path = controller_path.include?('/') ? controller_path.rpartition('/').first + '/' : ''
|
12
|
+
else
|
13
|
+
@controller_module_path = ''
|
14
|
+
end
|
15
|
+
|
12
16
|
@context = options[:context]
|
13
17
|
@key_formatter = options.fetch(:key_formatter, JSONAPI.configuration.key_formatter)
|
14
18
|
@errors = []
|
15
19
|
@warnings = []
|
16
|
-
@operations = []
|
17
|
-
@fields = {}
|
18
|
-
@filters = {}
|
19
|
-
@sort_criteria = nil
|
20
|
-
@source_klass = nil
|
21
|
-
@source_id = nil
|
22
|
-
@include_directives = nil
|
23
|
-
@paginator = nil
|
24
|
-
@id = nil
|
25
20
|
@server_error_callbacks = options.fetch(:server_error_callbacks, [])
|
21
|
+
end
|
26
22
|
|
27
|
-
|
23
|
+
def error_object_overrides
|
24
|
+
{}
|
28
25
|
end
|
29
26
|
|
30
|
-
def
|
27
|
+
def each(_response_document)
|
28
|
+
operation = setup_base_op(params)
|
29
|
+
if @errors.any?
|
30
|
+
fail JSONAPI::Exceptions::Errors.new(@errors)
|
31
|
+
else
|
32
|
+
yield operation
|
33
|
+
end
|
34
|
+
rescue ActionController::ParameterMissing => e
|
35
|
+
fail JSONAPI::Exceptions::ParameterMissing.new(e.param, error_object_overrides)
|
36
|
+
end
|
37
|
+
|
38
|
+
def transactional?
|
39
|
+
case params[:action]
|
40
|
+
when 'index', 'show_related_resource', 'index_related_resources', 'show', 'show_relationship'
|
41
|
+
return false
|
42
|
+
else
|
43
|
+
return true
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def setup_base_op(params)
|
31
48
|
return if params.nil?
|
32
49
|
|
33
|
-
|
50
|
+
resource_klass = Resource.resource_klass_for(params[:controller]) if params[:controller]
|
34
51
|
|
35
52
|
setup_action_method_name = "setup_#{params[:action]}_action"
|
36
53
|
if respond_to?(setup_action_method_name)
|
37
54
|
raise params[:_parser_exception] if params[:_parser_exception]
|
38
|
-
send(setup_action_method_name, params)
|
55
|
+
send(setup_action_method_name, params, resource_klass)
|
39
56
|
end
|
40
57
|
rescue ActionController::ParameterMissing => e
|
41
|
-
@errors.concat(JSONAPI::Exceptions::ParameterMissing.new(e.param).errors)
|
58
|
+
@errors.concat(JSONAPI::Exceptions::ParameterMissing.new(e.param, error_object_overrides).errors)
|
59
|
+
rescue JSONAPI::Exceptions::Error => e
|
60
|
+
e.error_object_overrides.merge! error_object_overrides
|
61
|
+
@errors.concat(e.errors)
|
42
62
|
end
|
43
63
|
|
44
|
-
def setup_index_action(params)
|
45
|
-
parse_fields(params[:fields])
|
46
|
-
parse_include_directives(params[:include])
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
64
|
+
def setup_index_action(params, resource_klass)
|
65
|
+
fields = parse_fields(resource_klass, params[:fields])
|
66
|
+
include_directives = parse_include_directives(resource_klass, params[:include])
|
67
|
+
filters = parse_filters(resource_klass, params[:filter])
|
68
|
+
sort_criteria = parse_sort_criteria(resource_klass, params[:sort])
|
69
|
+
paginator = parse_pagination(resource_klass, params[:page])
|
70
|
+
|
71
|
+
JSONAPI::Operation.new(
|
72
|
+
:find,
|
73
|
+
resource_klass,
|
74
|
+
context: context,
|
75
|
+
filters: filters,
|
76
|
+
include_directives: include_directives,
|
77
|
+
sort_criteria: sort_criteria,
|
78
|
+
paginator: paginator,
|
79
|
+
fields: fields
|
80
|
+
)
|
52
81
|
end
|
53
82
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
83
|
+
def setup_show_related_resource_action(params, resource_klass)
|
84
|
+
resolve_singleton_id(params, resource_klass)
|
85
|
+
source_klass = Resource.resource_klass_for(params.require(:source))
|
86
|
+
source_id = source_klass.verify_key(params.require(source_klass._as_parent_key), @context)
|
87
|
+
|
88
|
+
fields = parse_fields(resource_klass, params[:fields])
|
89
|
+
include_directives = parse_include_directives(resource_klass, params[:include])
|
90
|
+
|
91
|
+
relationship_type = params[:relationship].to_sym
|
92
|
+
|
93
|
+
JSONAPI::Operation.new(
|
94
|
+
:show_related_resource,
|
95
|
+
resource_klass,
|
96
|
+
context: @context,
|
97
|
+
relationship_type: relationship_type,
|
98
|
+
source_klass: source_klass,
|
99
|
+
source_id: source_id,
|
100
|
+
fields: fields,
|
101
|
+
include_directives: include_directives
|
102
|
+
)
|
63
103
|
end
|
64
104
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
105
|
+
def setup_index_related_resources_action(params, resource_klass)
|
106
|
+
resolve_singleton_id(params, resource_klass)
|
107
|
+
source_klass = Resource.resource_klass_for(params.require(:source))
|
108
|
+
source_id = source_klass.verify_key(params.require(source_klass._as_parent_key), @context)
|
109
|
+
|
110
|
+
fields = parse_fields(resource_klass, params[:fields])
|
111
|
+
include_directives = parse_include_directives(resource_klass, params[:include])
|
112
|
+
filters = parse_filters(resource_klass, params[:filter])
|
113
|
+
sort_criteria = parse_sort_criteria(resource_klass, params[:sort])
|
114
|
+
paginator = parse_pagination(resource_klass, params[:page])
|
115
|
+
relationship_type = params[:relationship]
|
116
|
+
|
117
|
+
JSONAPI::Operation.new(
|
118
|
+
:show_related_resources,
|
119
|
+
resource_klass,
|
120
|
+
context: @context,
|
121
|
+
relationship_type: relationship_type,
|
122
|
+
source_klass: source_klass,
|
123
|
+
source_id: source_id,
|
124
|
+
filters: filters,
|
125
|
+
sort_criteria: sort_criteria,
|
126
|
+
paginator: paginator,
|
127
|
+
fields: fields,
|
128
|
+
include_directives: include_directives
|
129
|
+
)
|
74
130
|
end
|
75
131
|
|
76
|
-
def setup_show_action(params)
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
132
|
+
def setup_show_action(params, resource_klass)
|
133
|
+
resolve_singleton_id(params, resource_klass)
|
134
|
+
fields = parse_fields(resource_klass, params[:fields])
|
135
|
+
include_directives = parse_include_directives(resource_klass, params[:include])
|
136
|
+
id = params[:id]
|
137
|
+
|
138
|
+
JSONAPI::Operation.new(
|
139
|
+
:show,
|
140
|
+
resource_klass,
|
141
|
+
context: @context,
|
142
|
+
id: id,
|
143
|
+
include_directives: include_directives,
|
144
|
+
fields: fields,
|
145
|
+
allowed_resources: params[:allowed_resources]
|
146
|
+
)
|
81
147
|
end
|
82
148
|
|
83
|
-
def setup_show_relationship_action(params)
|
84
|
-
|
149
|
+
def setup_show_relationship_action(params, resource_klass)
|
150
|
+
resolve_singleton_id(params, resource_klass)
|
151
|
+
relationship_type = params[:relationship]
|
152
|
+
parent_key = params.require(resource_klass._as_parent_key)
|
153
|
+
include_directives = parse_include_directives(resource_klass, params[:include])
|
154
|
+
filters = parse_filters(resource_klass, params[:filter])
|
155
|
+
sort_criteria = parse_sort_criteria(resource_klass, params[:sort])
|
156
|
+
paginator = parse_pagination(resource_klass, params[:page])
|
157
|
+
|
158
|
+
JSONAPI::Operation.new(
|
159
|
+
:show_relationship,
|
160
|
+
resource_klass,
|
161
|
+
context: @context,
|
162
|
+
relationship_type: relationship_type,
|
163
|
+
parent_key: resource_klass.verify_key(parent_key),
|
164
|
+
filters: filters,
|
165
|
+
sort_criteria: sort_criteria,
|
166
|
+
paginator: paginator,
|
167
|
+
fields: fields,
|
168
|
+
include_directives: include_directives
|
169
|
+
)
|
85
170
|
end
|
86
171
|
|
87
|
-
def setup_create_action(params)
|
88
|
-
parse_fields(params[:fields])
|
89
|
-
parse_include_directives(params[:include])
|
90
|
-
|
172
|
+
def setup_create_action(params, resource_klass)
|
173
|
+
fields = parse_fields(resource_klass, params[:fields])
|
174
|
+
include_directives = parse_include_directives(resource_klass, params[:include])
|
175
|
+
|
176
|
+
data = params.require(:data)
|
177
|
+
|
178
|
+
unless data.respond_to?(:each_pair)
|
179
|
+
fail JSONAPI::Exceptions::InvalidDataFormat.new(error_object_overrides)
|
180
|
+
end
|
181
|
+
|
182
|
+
verify_type(data[:type], resource_klass)
|
183
|
+
|
184
|
+
data = parse_params(resource_klass, data, resource_klass.creatable_fields(@context))
|
185
|
+
|
186
|
+
JSONAPI::Operation.new(
|
187
|
+
:create_resource,
|
188
|
+
resource_klass,
|
189
|
+
context: @context,
|
190
|
+
data: data,
|
191
|
+
fields: fields,
|
192
|
+
include_directives: include_directives,
|
193
|
+
warnings: @warnings
|
194
|
+
)
|
91
195
|
end
|
92
196
|
|
93
|
-
def setup_create_relationship_action(params)
|
94
|
-
|
197
|
+
def setup_create_relationship_action(params, resource_klass)
|
198
|
+
resolve_singleton_id(params, resource_klass)
|
199
|
+
parse_modify_relationship_action(:add, params, resource_klass)
|
95
200
|
end
|
96
201
|
|
97
|
-
def setup_update_relationship_action(params)
|
98
|
-
parse_modify_relationship_action(params,
|
202
|
+
def setup_update_relationship_action(params, resource_klass)
|
203
|
+
parse_modify_relationship_action(:update, params, resource_klass)
|
99
204
|
end
|
100
205
|
|
101
|
-
def setup_update_action(params)
|
102
|
-
|
103
|
-
|
104
|
-
|
206
|
+
def setup_update_action(params, resource_klass)
|
207
|
+
resolve_singleton_id(params, resource_klass)
|
208
|
+
fields = parse_fields(resource_klass, params[:fields])
|
209
|
+
include_directives = parse_include_directives(resource_klass, params[:include])
|
210
|
+
|
211
|
+
data = params.require(:data)
|
212
|
+
key = params[:id]
|
213
|
+
|
214
|
+
fail JSONAPI::Exceptions::InvalidDataFormat.new(error_object_overrides) unless data.respond_to?(:each_pair)
|
215
|
+
|
216
|
+
fail JSONAPI::Exceptions::MissingKey.new(error_object_overrides) if data[:id].nil?
|
217
|
+
|
218
|
+
resource_id = data.require(:id)
|
219
|
+
# Singleton resources may not have the ID set in the URL
|
220
|
+
if key
|
221
|
+
fail JSONAPI::Exceptions::KeyNotIncludedInURL.new(resource_id) if key.to_s != resource_id.to_s
|
222
|
+
end
|
223
|
+
|
224
|
+
data.delete(:id)
|
225
|
+
|
226
|
+
verify_type(data[:type], resource_klass)
|
227
|
+
|
228
|
+
JSONAPI::Operation.new(
|
229
|
+
:replace_fields,
|
230
|
+
resource_klass,
|
231
|
+
context: @context,
|
232
|
+
resource_id: resource_id,
|
233
|
+
data: parse_params(resource_klass, data, resource_klass.updatable_fields(@context)),
|
234
|
+
fields: fields,
|
235
|
+
include_directives: include_directives,
|
236
|
+
warnings: @warnings
|
237
|
+
)
|
105
238
|
end
|
106
239
|
|
107
|
-
def setup_destroy_action(params)
|
108
|
-
|
240
|
+
def setup_destroy_action(params, resource_klass)
|
241
|
+
resolve_singleton_id(params, resource_klass)
|
242
|
+
JSONAPI::Operation.new(
|
243
|
+
:remove_resource,
|
244
|
+
resource_klass,
|
245
|
+
context: @context,
|
246
|
+
resource_id: resource_klass.verify_key(params.require(:id), @context))
|
109
247
|
end
|
110
248
|
|
111
|
-
def setup_destroy_relationship_action(params)
|
112
|
-
|
249
|
+
def setup_destroy_relationship_action(params, resource_klass)
|
250
|
+
resolve_singleton_id(params, resource_klass)
|
251
|
+
parse_modify_relationship_action(:remove, params, resource_klass)
|
113
252
|
end
|
114
253
|
|
115
|
-
def parse_modify_relationship_action(params,
|
254
|
+
def parse_modify_relationship_action(modification_type, params, resource_klass)
|
116
255
|
relationship_type = params.require(:relationship)
|
117
|
-
|
118
|
-
|
256
|
+
|
257
|
+
parent_key = params.require(resource_klass._as_parent_key)
|
258
|
+
relationship = resource_klass._relationship(relationship_type)
|
119
259
|
|
120
260
|
# Removals of to-one relationships are done implicitly and require no specification of data
|
121
261
|
data_required = !(modification_type == :remove && relationship.is_a?(JSONAPI::Relationship::ToOne))
|
@@ -123,75 +263,74 @@ module JSONAPI
|
|
123
263
|
if data_required
|
124
264
|
data = params.fetch(:data)
|
125
265
|
object_params = { relationships: { format_key(relationship.name) => { data: data } } }
|
126
|
-
verified_params = parse_params(object_params, @resource_klass.updatable_fields(@context))
|
127
266
|
|
128
|
-
|
267
|
+
verified_params = parse_params(resource_klass, object_params, resource_klass.updatable_fields(@context))
|
268
|
+
|
269
|
+
parse_arguments = [resource_klass, verified_params, relationship, parent_key]
|
129
270
|
else
|
130
|
-
parse_arguments = [params, relationship, parent_key]
|
271
|
+
parse_arguments = [resource_klass, params, relationship, parent_key]
|
131
272
|
end
|
132
273
|
|
133
274
|
send(:"parse_#{modification_type}_relationship_operation", *parse_arguments)
|
134
275
|
end
|
135
276
|
|
136
|
-
def
|
137
|
-
|
138
|
-
|
277
|
+
def parse_pagination(resource_klass, page)
|
278
|
+
paginator_name = resource_klass._paginator
|
279
|
+
JSONAPI::Paginator.paginator_for(paginator_name).new(page) unless paginator_name == :none
|
139
280
|
end
|
140
281
|
|
141
|
-
def
|
142
|
-
paginator_name = @resource_klass._paginator
|
143
|
-
@paginator = JSONAPI::Paginator.paginator_for(paginator_name).new(page) unless paginator_name == :none
|
144
|
-
rescue JSONAPI::Exceptions::Error => e
|
145
|
-
@errors.concat(e.errors)
|
146
|
-
end
|
147
|
-
|
148
|
-
def parse_fields(fields)
|
149
|
-
return if fields.nil?
|
150
|
-
|
282
|
+
def parse_fields(resource_klass, fields)
|
151
283
|
extracted_fields = {}
|
152
284
|
|
285
|
+
return extracted_fields if fields.nil?
|
286
|
+
|
153
287
|
# Extract the fields for each type from the fields parameters
|
154
288
|
if fields.is_a?(ActionController::Parameters)
|
155
289
|
fields.each do |field, value|
|
156
|
-
|
290
|
+
if value.is_a?(Array)
|
291
|
+
resource_fields = value
|
292
|
+
else
|
293
|
+
resource_fields = value.split(',') unless value.nil? || value.empty?
|
294
|
+
end
|
157
295
|
extracted_fields[field] = resource_fields
|
158
296
|
end
|
159
297
|
else
|
160
|
-
fail JSONAPI::Exceptions::InvalidFieldFormat.new
|
298
|
+
fail JSONAPI::Exceptions::InvalidFieldFormat.new(error_object_overrides)
|
161
299
|
end
|
162
300
|
|
163
301
|
# Validate the fields
|
302
|
+
validated_fields = {}
|
164
303
|
extracted_fields.each do |type, values|
|
165
304
|
underscored_type = unformat_key(type)
|
166
|
-
|
305
|
+
validated_fields[type] = []
|
167
306
|
begin
|
168
307
|
if type != format_key(type)
|
169
|
-
fail JSONAPI::Exceptions::InvalidResource.new(type)
|
308
|
+
fail JSONAPI::Exceptions::InvalidResource.new(type, error_object_overrides)
|
170
309
|
end
|
171
|
-
type_resource = Resource.
|
310
|
+
type_resource = Resource.resource_klass_for(resource_klass.module_path + underscored_type.to_s)
|
172
311
|
rescue NameError
|
173
|
-
fail JSONAPI::Exceptions::InvalidResource.new(type)
|
312
|
+
fail JSONAPI::Exceptions::InvalidResource.new(type, error_object_overrides)
|
174
313
|
end
|
175
314
|
|
176
315
|
if type_resource.nil?
|
177
|
-
fail JSONAPI::Exceptions::InvalidResource.new(type)
|
316
|
+
fail JSONAPI::Exceptions::InvalidResource.new(type, error_object_overrides)
|
178
317
|
else
|
179
318
|
unless values.nil?
|
180
319
|
valid_fields = type_resource.fields.collect { |key| format_key(key) }
|
181
320
|
values.each do |field|
|
182
321
|
if valid_fields.include?(field)
|
183
|
-
|
322
|
+
validated_fields[type].push unformat_key(field)
|
184
323
|
else
|
185
|
-
fail JSONAPI::Exceptions::InvalidField.new(type, field)
|
324
|
+
fail JSONAPI::Exceptions::InvalidField.new(type, field, error_object_overrides)
|
186
325
|
end
|
187
326
|
end
|
188
327
|
else
|
189
|
-
fail JSONAPI::Exceptions::InvalidField.new(type, 'nil')
|
328
|
+
fail JSONAPI::Exceptions::InvalidField.new(type, 'nil', error_object_overrides)
|
190
329
|
end
|
191
330
|
end
|
192
331
|
end
|
193
332
|
|
194
|
-
|
333
|
+
validated_fields.deep_transform_keys { |key| unformat_key(key) }
|
195
334
|
end
|
196
335
|
|
197
336
|
def check_include(resource_klass, include_parts)
|
@@ -199,214 +338,144 @@ module JSONAPI
|
|
199
338
|
|
200
339
|
relationship = resource_klass._relationship(relationship_name)
|
201
340
|
if relationship && format_key(relationship_name) == include_parts.first
|
341
|
+
unless relationship.allow_include?(context)
|
342
|
+
fail JSONAPI::Exceptions::InvalidInclude.new(format_key(resource_klass._type), include_parts.first)
|
343
|
+
end
|
344
|
+
|
202
345
|
unless include_parts.last.empty?
|
203
|
-
check_include(Resource.
|
346
|
+
check_include(Resource.resource_klass_for(resource_klass.module_path + relationship.class_name.to_s.underscore),
|
347
|
+
include_parts.last.partition('.'))
|
204
348
|
end
|
205
349
|
else
|
206
350
|
fail JSONAPI::Exceptions::InvalidInclude.new(format_key(resource_klass._type), include_parts.first)
|
207
351
|
end
|
352
|
+
true
|
208
353
|
end
|
209
354
|
|
210
|
-
def parse_include_directives(raw_include)
|
211
|
-
|
212
|
-
|
213
|
-
unless JSONAPI.configuration.allow_include
|
214
|
-
fail JSONAPI::Exceptions::ParameterNotAllowed.new(:include)
|
215
|
-
end
|
355
|
+
def parse_include_directives(resource_klass, raw_include)
|
356
|
+
raw_include ||= ''
|
216
357
|
|
217
358
|
included_resources = []
|
218
359
|
begin
|
219
|
-
included_resources += CSV.parse_line(raw_include)
|
360
|
+
included_resources += raw_include.is_a?(Array) ? raw_include : CSV.parse_line(raw_include) || []
|
220
361
|
rescue CSV::MalformedCSVError
|
221
|
-
fail JSONAPI::Exceptions::InvalidInclude.new(format_key(
|
362
|
+
fail JSONAPI::Exceptions::InvalidInclude.new(format_key(resource_klass._type), raw_include)
|
222
363
|
end
|
223
364
|
|
224
|
-
return if included_resources.empty?
|
225
|
-
|
226
365
|
begin
|
227
366
|
result = included_resources.compact.map do |included_resource|
|
228
|
-
check_include(
|
367
|
+
check_include(resource_klass, included_resource.partition('.'))
|
229
368
|
unformat_key(included_resource).to_s
|
230
369
|
end
|
231
370
|
|
232
|
-
|
371
|
+
return JSONAPI::IncludeDirectives.new(resource_klass, result)
|
233
372
|
rescue JSONAPI::Exceptions::InvalidInclude => e
|
234
373
|
@errors.concat(e.errors)
|
235
|
-
|
374
|
+
return {}
|
236
375
|
end
|
237
376
|
end
|
238
377
|
|
239
|
-
def parse_filters(filters)
|
240
|
-
|
378
|
+
def parse_filters(resource_klass, filters)
|
379
|
+
parsed_filters = {}
|
241
380
|
|
242
|
-
|
243
|
-
|
381
|
+
# apply default filters
|
382
|
+
resource_klass._allowed_filters.each do |filter, opts|
|
383
|
+
next if opts[:default].nil? || !parsed_filters[filter].nil?
|
384
|
+
parsed_filters[filter] = opts[:default]
|
244
385
|
end
|
245
386
|
|
387
|
+
return parsed_filters unless filters
|
388
|
+
|
246
389
|
unless filters.class.method_defined?(:each)
|
247
390
|
@errors.concat(JSONAPI::Exceptions::InvalidFiltersSyntax.new(filters).errors)
|
248
|
-
return
|
391
|
+
return {}
|
392
|
+
end
|
393
|
+
|
394
|
+
unless JSONAPI.configuration.allow_filter
|
395
|
+
fail JSONAPI::Exceptions::ParameterNotAllowed.new(:filter)
|
249
396
|
end
|
250
397
|
|
251
398
|
filters.each do |key, value|
|
252
399
|
filter = unformat_key(key)
|
253
|
-
if
|
254
|
-
|
400
|
+
if resource_klass._allowed_filter?(filter)
|
401
|
+
parsed_filters[filter] = value
|
255
402
|
else
|
256
|
-
fail JSONAPI::Exceptions::FilterNotAllowed.new(
|
403
|
+
fail JSONAPI::Exceptions::FilterNotAllowed.new(key)
|
257
404
|
end
|
258
405
|
end
|
259
|
-
end
|
260
406
|
|
261
|
-
|
262
|
-
@resource_klass._allowed_filters.each do |filter, opts|
|
263
|
-
next if opts[:default].nil? || !@filters[filter].nil?
|
264
|
-
@filters[filter] = opts[:default]
|
265
|
-
end
|
407
|
+
parsed_filters
|
266
408
|
end
|
267
409
|
|
268
|
-
def parse_sort_criteria(sort_criteria)
|
410
|
+
def parse_sort_criteria(resource_klass, sort_criteria)
|
269
411
|
return unless sort_criteria.present?
|
270
412
|
|
271
413
|
unless JSONAPI.configuration.allow_sort
|
272
414
|
fail JSONAPI::Exceptions::ParameterNotAllowed.new(:sort)
|
273
415
|
end
|
274
416
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
417
|
+
if sort_criteria.is_a?(Array)
|
418
|
+
sorts = sort_criteria
|
419
|
+
elsif sort_criteria.is_a?(String)
|
420
|
+
begin
|
421
|
+
raw = URI.decode_www_form_component(sort_criteria)
|
422
|
+
sorts = CSV.parse_line(raw)
|
423
|
+
rescue CSV::MalformedCSVError
|
424
|
+
fail JSONAPI::Exceptions::InvalidSortCriteria.new(format_key(resource_klass._type), raw)
|
425
|
+
end
|
281
426
|
end
|
282
427
|
|
283
428
|
@sort_criteria = sorts.collect do |sort|
|
284
429
|
if sort.start_with?('-')
|
285
|
-
|
286
|
-
|
430
|
+
criteria = { field: unformat_key(sort[1..-1]).to_s }
|
431
|
+
criteria[:direction] = :desc
|
287
432
|
else
|
288
|
-
|
289
|
-
|
433
|
+
criteria = { field: unformat_key(sort).to_s }
|
434
|
+
criteria[:direction] = :asc
|
290
435
|
end
|
291
436
|
|
292
|
-
check_sort_criteria(
|
293
|
-
|
437
|
+
check_sort_criteria(resource_klass, criteria)
|
438
|
+
criteria
|
294
439
|
end
|
295
440
|
end
|
296
441
|
|
297
442
|
def check_sort_criteria(resource_klass, sort_criteria)
|
298
443
|
sort_field = sort_criteria[:field]
|
299
|
-
sortable_fields = resource_klass.sortable_fields(context)
|
300
444
|
|
301
|
-
unless
|
445
|
+
unless resource_klass.sortable_field?(sort_field.to_sym, context)
|
302
446
|
fail JSONAPI::Exceptions::InvalidSortCriteria.new(format_key(resource_klass._type), sort_field)
|
303
447
|
end
|
304
448
|
end
|
305
449
|
|
306
|
-
def
|
307
|
-
@operations.push JSONAPI::Operation.new(:find,
|
308
|
-
@resource_klass,
|
309
|
-
context: @context,
|
310
|
-
filters: @filters,
|
311
|
-
include_directives: @include_directives,
|
312
|
-
sort_criteria: @sort_criteria,
|
313
|
-
paginator: @paginator,
|
314
|
-
fields: @fields
|
315
|
-
)
|
316
|
-
end
|
317
|
-
|
318
|
-
def add_show_operation
|
319
|
-
@operations.push JSONAPI::Operation.new(:show,
|
320
|
-
@resource_klass,
|
321
|
-
context: @context,
|
322
|
-
id: @id,
|
323
|
-
include_directives: @include_directives,
|
324
|
-
fields: @fields
|
325
|
-
)
|
326
|
-
end
|
327
|
-
|
328
|
-
def add_show_relationship_operation(relationship_type, parent_key)
|
329
|
-
@operations.push JSONAPI::Operation.new(:show_relationship,
|
330
|
-
@resource_klass,
|
331
|
-
context: @context,
|
332
|
-
relationship_type: relationship_type,
|
333
|
-
parent_key: @resource_klass.verify_key(parent_key)
|
334
|
-
)
|
335
|
-
end
|
336
|
-
|
337
|
-
def add_show_related_resource_operation(relationship_type)
|
338
|
-
@operations.push JSONAPI::Operation.new(:show_related_resource,
|
339
|
-
@resource_klass,
|
340
|
-
context: @context,
|
341
|
-
relationship_type: relationship_type,
|
342
|
-
source_klass: @source_klass,
|
343
|
-
source_id: @source_id,
|
344
|
-
fields: @fields,
|
345
|
-
include_directives: @include_directives
|
346
|
-
)
|
347
|
-
end
|
348
|
-
|
349
|
-
def add_show_related_resources_operation(relationship_type)
|
350
|
-
@operations.push JSONAPI::Operation.new(:show_related_resources,
|
351
|
-
@resource_klass,
|
352
|
-
context: @context,
|
353
|
-
relationship_type: relationship_type,
|
354
|
-
source_klass: @source_klass,
|
355
|
-
source_id: @source_id,
|
356
|
-
filters: @filters,
|
357
|
-
sort_criteria: @sort_criteria,
|
358
|
-
paginator: @paginator,
|
359
|
-
fields: @fields,
|
360
|
-
include_directives: @include_directives
|
361
|
-
)
|
362
|
-
end
|
363
|
-
|
364
|
-
def parse_add_operation(params)
|
365
|
-
fail JSONAPI::Exceptions::InvalidDataFormat unless params.respond_to?(:each_pair)
|
366
|
-
|
367
|
-
verify_type(params[:type])
|
368
|
-
|
369
|
-
data = parse_params(params, @resource_klass.creatable_fields(@context))
|
370
|
-
@operations.push JSONAPI::Operation.new(:create_resource,
|
371
|
-
@resource_klass,
|
372
|
-
context: @context,
|
373
|
-
data: data,
|
374
|
-
fields: @fields,
|
375
|
-
include_directives: @include_directives
|
376
|
-
)
|
377
|
-
rescue JSONAPI::Exceptions::Error => e
|
378
|
-
@errors.concat(e.errors)
|
379
|
-
end
|
380
|
-
|
381
|
-
def verify_type(type)
|
450
|
+
def verify_type(type, resource_klass)
|
382
451
|
if type.nil?
|
383
452
|
fail JSONAPI::Exceptions::ParameterMissing.new(:type)
|
384
|
-
elsif unformat_key(type).to_sym !=
|
385
|
-
fail JSONAPI::Exceptions::InvalidResource.new(type)
|
453
|
+
elsif unformat_key(type).to_sym != resource_klass._type
|
454
|
+
fail JSONAPI::Exceptions::InvalidResource.new(type, error_object_overrides)
|
386
455
|
end
|
387
456
|
end
|
388
457
|
|
389
458
|
def parse_to_one_links_object(raw)
|
390
459
|
if raw.nil?
|
391
460
|
return {
|
392
|
-
|
393
|
-
|
461
|
+
type: nil,
|
462
|
+
id: nil
|
394
463
|
}
|
395
464
|
end
|
396
465
|
|
397
466
|
if !(raw.is_a?(Hash) || raw.is_a?(ActionController::Parameters)) ||
|
398
|
-
|
399
|
-
fail JSONAPI::Exceptions::InvalidLinksObject.new
|
467
|
+
raw.keys.length != 2 || !(raw.key?('type') && raw.key?('id'))
|
468
|
+
fail JSONAPI::Exceptions::InvalidLinksObject.new(error_object_overrides)
|
400
469
|
end
|
401
470
|
|
402
471
|
{
|
403
|
-
|
404
|
-
|
472
|
+
type: unformat_key(raw['type']).to_s,
|
473
|
+
id: raw['id']
|
405
474
|
}
|
406
475
|
end
|
407
476
|
|
408
477
|
def parse_to_many_links_object(raw)
|
409
|
-
fail JSONAPI::Exceptions::InvalidLinksObject.new if raw.nil?
|
478
|
+
fail JSONAPI::Exceptions::InvalidLinksObject.new(error_object_overrides) if raw.nil?
|
410
479
|
|
411
480
|
links_object = {}
|
412
481
|
if raw.is_a?(Array)
|
@@ -416,12 +485,12 @@ module JSONAPI
|
|
416
485
|
links_object[link_object[:type]].push(link_object[:id])
|
417
486
|
end
|
418
487
|
else
|
419
|
-
fail JSONAPI::Exceptions::InvalidLinksObject.new
|
488
|
+
fail JSONAPI::Exceptions::InvalidLinksObject.new(error_object_overrides)
|
420
489
|
end
|
421
490
|
links_object
|
422
491
|
end
|
423
492
|
|
424
|
-
def parse_params(params, allowed_fields)
|
493
|
+
def parse_params(resource_klass, params, allowed_fields)
|
425
494
|
verify_permitted_params(params, allowed_fields)
|
426
495
|
|
427
496
|
checked_attributes = {}
|
@@ -430,37 +499,37 @@ module JSONAPI
|
|
430
499
|
|
431
500
|
params.each do |key, value|
|
432
501
|
case key.to_s
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
502
|
+
when 'relationships'
|
503
|
+
value.each do |link_key, link_value|
|
504
|
+
param = unformat_key(link_key)
|
505
|
+
relationship = resource_klass._relationship(param)
|
506
|
+
|
507
|
+
if relationship.is_a?(JSONAPI::Relationship::ToOne)
|
508
|
+
checked_to_one_relationships[param] = parse_to_one_relationship(resource_klass, link_value, relationship)
|
509
|
+
elsif relationship.is_a?(JSONAPI::Relationship::ToMany)
|
510
|
+
parse_to_many_relationship(resource_klass, link_value, relationship) do |result_val|
|
511
|
+
checked_to_many_relationships[param] = result_val
|
512
|
+
end
|
443
513
|
end
|
444
514
|
end
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
end
|
515
|
+
when 'id'
|
516
|
+
checked_attributes['id'] = unformat_value(resource_klass, :id, value)
|
517
|
+
when 'attributes'
|
518
|
+
value.each do |key, value|
|
519
|
+
param = unformat_key(key)
|
520
|
+
checked_attributes[param] = unformat_value(resource_klass, param, value)
|
521
|
+
end
|
453
522
|
end
|
454
523
|
end
|
455
524
|
|
456
525
|
return {
|
457
|
-
|
458
|
-
|
459
|
-
|
526
|
+
'attributes' => checked_attributes,
|
527
|
+
'to_one' => checked_to_one_relationships,
|
528
|
+
'to_many' => checked_to_many_relationships
|
460
529
|
}.deep_transform_keys { |key| unformat_key(key) }
|
461
530
|
end
|
462
531
|
|
463
|
-
def parse_to_one_relationship(link_value, relationship)
|
532
|
+
def parse_to_one_relationship(resource_klass, link_value, relationship)
|
464
533
|
if link_value.nil?
|
465
534
|
linkage = nil
|
466
535
|
else
|
@@ -469,12 +538,12 @@ module JSONAPI
|
|
469
538
|
|
470
539
|
links_object = parse_to_one_links_object(linkage)
|
471
540
|
if !relationship.polymorphic? && links_object[:type] && (links_object[:type].to_s != relationship.type.to_s)
|
472
|
-
fail JSONAPI::Exceptions::TypeMismatch.new(links_object[:type])
|
541
|
+
fail JSONAPI::Exceptions::TypeMismatch.new(links_object[:type], error_object_overrides)
|
473
542
|
end
|
474
543
|
|
475
544
|
unless links_object[:id].nil?
|
476
|
-
resource =
|
477
|
-
relationship_resource = resource.
|
545
|
+
resource = resource_klass || Resource
|
546
|
+
relationship_resource = resource.resource_klass_for(unformat_key(relationship.options[:class_name] || links_object[:type]).to_s)
|
478
547
|
relationship_id = relationship_resource.verify_key(links_object[:id], @context)
|
479
548
|
if relationship.polymorphic?
|
480
549
|
{ id: relationship_id, type: unformat_key(links_object[:type].to_s) }
|
@@ -486,37 +555,54 @@ module JSONAPI
|
|
486
555
|
end
|
487
556
|
end
|
488
557
|
|
489
|
-
def parse_to_many_relationship(link_value, relationship, &add_result)
|
490
|
-
if link_value.is_a?(
|
491
|
-
linkage = []
|
492
|
-
elsif (link_value.is_a?(Hash) || link_value.is_a?(ActionController::Parameters))
|
558
|
+
def parse_to_many_relationship(resource_klass, link_value, relationship, &add_result)
|
559
|
+
if (link_value.is_a?(Hash) || link_value.is_a?(ActionController::Parameters))
|
493
560
|
linkage = link_value[:data]
|
494
561
|
else
|
495
|
-
fail JSONAPI::Exceptions::InvalidLinksObject.new
|
562
|
+
fail JSONAPI::Exceptions::InvalidLinksObject.new(error_object_overrides)
|
496
563
|
end
|
497
564
|
|
498
565
|
links_object = parse_to_many_links_object(linkage)
|
499
566
|
|
500
|
-
# Since we do not yet support polymorphic to_many relationships we will raise an error if the type does not match the
|
501
|
-
# relationship's type.
|
502
|
-
# ToDo: Support Polymorphic relationships
|
503
|
-
|
504
567
|
if links_object.length == 0
|
505
568
|
add_result.call([])
|
506
569
|
else
|
507
|
-
if
|
508
|
-
|
509
|
-
|
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
|
578
|
+
|
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
|
510
597
|
|
511
|
-
|
512
|
-
|
513
|
-
add_result.call relationship_resource.verify_keys(keys, @context)
|
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)
|
514
600
|
end
|
515
601
|
end
|
516
602
|
end
|
517
603
|
|
518
|
-
def unformat_value(attribute, value)
|
519
|
-
value_formatter = JSONAPI::ValueFormatter.value_formatter_for(
|
604
|
+
def unformat_value(resource_klass, attribute, value)
|
605
|
+
value_formatter = JSONAPI::ValueFormatter.value_formatter_for(resource_klass._attribute_options(attribute)[:format])
|
520
606
|
value_formatter.unformat(value)
|
521
607
|
end
|
522
608
|
|
@@ -526,45 +612,45 @@ module JSONAPI
|
|
526
612
|
|
527
613
|
params.each do |key, value|
|
528
614
|
case key.to_s
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
615
|
+
when 'relationships'
|
616
|
+
value.keys.each do |links_key|
|
617
|
+
unless formatted_allowed_fields.include?(links_key.to_sym)
|
618
|
+
if JSONAPI.configuration.raise_if_parameters_not_allowed
|
619
|
+
fail JSONAPI::Exceptions::ParameterNotAllowed.new(links_key, error_object_overrides)
|
620
|
+
else
|
621
|
+
params_not_allowed.push(links_key)
|
622
|
+
value.delete links_key
|
623
|
+
end
|
537
624
|
end
|
538
625
|
end
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
626
|
+
when 'attributes'
|
627
|
+
value.each do |attr_key, _attr_value|
|
628
|
+
unless formatted_allowed_fields.include?(attr_key.to_sym)
|
629
|
+
if JSONAPI.configuration.raise_if_parameters_not_allowed
|
630
|
+
fail JSONAPI::Exceptions::ParameterNotAllowed.new(attr_key, error_object_overrides)
|
631
|
+
else
|
632
|
+
params_not_allowed.push(attr_key)
|
633
|
+
value.delete attr_key
|
634
|
+
end
|
635
|
+
end
|
636
|
+
end
|
637
|
+
when 'type'
|
638
|
+
when 'id'
|
639
|
+
unless formatted_allowed_fields.include?(:id)
|
543
640
|
if JSONAPI.configuration.raise_if_parameters_not_allowed
|
544
|
-
fail JSONAPI::Exceptions::ParameterNotAllowed.new(
|
641
|
+
fail JSONAPI::Exceptions::ParameterNotAllowed.new(:id, error_object_overrides)
|
545
642
|
else
|
546
|
-
params_not_allowed.push(
|
547
|
-
|
643
|
+
params_not_allowed.push(:id)
|
644
|
+
params.delete :id
|
548
645
|
end
|
549
646
|
end
|
550
|
-
|
551
|
-
when 'type'
|
552
|
-
when 'id'
|
553
|
-
unless formatted_allowed_fields.include?(:id)
|
647
|
+
else
|
554
648
|
if JSONAPI.configuration.raise_if_parameters_not_allowed
|
555
|
-
fail JSONAPI::Exceptions::ParameterNotAllowed.new(
|
649
|
+
fail JSONAPI::Exceptions::ParameterNotAllowed.new(key, error_object_overrides)
|
556
650
|
else
|
557
|
-
params_not_allowed.push(
|
558
|
-
params.delete
|
651
|
+
params_not_allowed.push(key)
|
652
|
+
params.delete key
|
559
653
|
end
|
560
|
-
end
|
561
|
-
else
|
562
|
-
if JSONAPI.configuration.raise_if_parameters_not_allowed
|
563
|
-
fail JSONAPI::Exceptions::ParameterNotAllowed.new(key)
|
564
|
-
else
|
565
|
-
params_not_allowed.push(key)
|
566
|
-
params.delete key
|
567
|
-
end
|
568
654
|
end
|
569
655
|
end
|
570
656
|
|
@@ -578,23 +664,24 @@ module JSONAPI
|
|
578
664
|
end
|
579
665
|
end
|
580
666
|
|
581
|
-
def parse_add_relationship_operation(verified_params, relationship, parent_key)
|
667
|
+
def parse_add_relationship_operation(resource_klass, verified_params, relationship, parent_key)
|
582
668
|
if relationship.is_a?(JSONAPI::Relationship::ToMany)
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
669
|
+
return JSONAPI::Operation.new(
|
670
|
+
:create_to_many_relationships,
|
671
|
+
resource_klass,
|
672
|
+
context: @context,
|
673
|
+
resource_id: parent_key,
|
674
|
+
relationship_type: relationship.name,
|
675
|
+
data: verified_params[:to_many].values[0]
|
589
676
|
)
|
590
677
|
end
|
591
678
|
end
|
592
679
|
|
593
|
-
def parse_update_relationship_operation(verified_params, relationship, parent_key)
|
680
|
+
def parse_update_relationship_operation(resource_klass, verified_params, relationship, parent_key)
|
594
681
|
options = {
|
595
|
-
|
596
|
-
|
597
|
-
|
682
|
+
context: @context,
|
683
|
+
resource_id: parent_key,
|
684
|
+
relationship_type: relationship.name
|
598
685
|
}
|
599
686
|
|
600
687
|
if relationship.is_a?(JSONAPI::Relationship::ToOne)
|
@@ -615,62 +702,30 @@ module JSONAPI
|
|
615
702
|
operation_type = :replace_to_many_relationships
|
616
703
|
end
|
617
704
|
|
618
|
-
|
705
|
+
JSONAPI::Operation.new(operation_type, resource_klass, options)
|
619
706
|
end
|
620
707
|
|
621
|
-
def
|
622
|
-
fail JSONAPI::Exceptions::InvalidDataFormat unless data.respond_to?(:each_pair)
|
623
|
-
|
624
|
-
fail JSONAPI::Exceptions::MissingKey.new if data[:id].nil?
|
625
|
-
|
626
|
-
key = data[:id].to_s
|
627
|
-
if id_key_presence_check_required && !keys.include?(key)
|
628
|
-
fail JSONAPI::Exceptions::KeyNotIncludedInURL.new(key)
|
629
|
-
end
|
630
|
-
|
631
|
-
data.delete(:id) unless keys.include?(:id)
|
632
|
-
|
633
|
-
verify_type(data[:type])
|
634
|
-
|
635
|
-
@operations.push JSONAPI::Operation.new(:replace_fields,
|
636
|
-
@resource_klass,
|
637
|
-
context: @context,
|
638
|
-
resource_id: key,
|
639
|
-
data: parse_params(data, @resource_klass.updatable_fields(@context)),
|
640
|
-
fields: @fields,
|
641
|
-
include_directives: @include_directives
|
642
|
-
)
|
643
|
-
end
|
644
|
-
|
645
|
-
def parse_replace_operation(data, keys)
|
646
|
-
parse_single_replace_operation(data, [keys], id_key_presence_check_required: keys.present?)
|
647
|
-
rescue JSONAPI::Exceptions::Error => e
|
648
|
-
@errors.concat(e.errors)
|
649
|
-
end
|
650
|
-
|
651
|
-
def parse_remove_operation(params)
|
652
|
-
@operations.push JSONAPI::Operation.new(:remove_resource,
|
653
|
-
@resource_klass,
|
654
|
-
context: @context,
|
655
|
-
resource_id: @resource_klass.verify_key(params.require(:id), context))
|
656
|
-
rescue JSONAPI::Exceptions::Error => e
|
657
|
-
@errors.concat(e.errors)
|
658
|
-
end
|
659
|
-
|
660
|
-
def parse_remove_relationship_operation(params, relationship, parent_key)
|
708
|
+
def parse_remove_relationship_operation(resource_klass, params, relationship, parent_key)
|
661
709
|
operation_base_args = [resource_klass].push(
|
662
|
-
|
663
|
-
|
664
|
-
|
710
|
+
context: @context,
|
711
|
+
resource_id: parent_key,
|
712
|
+
relationship_type: relationship.name
|
665
713
|
)
|
666
714
|
|
667
715
|
if relationship.is_a?(JSONAPI::Relationship::ToMany)
|
668
716
|
operation_args = operation_base_args.dup
|
669
717
|
keys = params[:to_many].values[0]
|
670
718
|
operation_args[1] = operation_args[1].merge(associated_keys: keys)
|
671
|
-
|
719
|
+
JSONAPI::Operation.new(:remove_to_many_relationships, *operation_args)
|
672
720
|
else
|
673
|
-
|
721
|
+
JSONAPI::Operation.new(:remove_to_one_relationship, *operation_base_args)
|
722
|
+
end
|
723
|
+
end
|
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
|
674
729
|
end
|
675
730
|
end
|
676
731
|
|