jsonapi-resources 0.9.0 → 0.10.6
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 +303 -0
- data/lib/jsonapi/active_relation_resource.rb +884 -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 +71 -8
- data/lib/jsonapi/error.rb +27 -0
- data/lib/jsonapi/error_codes.rb +2 -0
- data/lib/jsonapi/exceptions.rb +80 -50
- 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 +239 -111
- data/lib/jsonapi/relationship.rb +153 -15
- data/lib/jsonapi/request_parser.rb +430 -367
- data/lib/jsonapi/resource.rb +3 -1253
- 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 +50 -20
- 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,77 +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
|
-
|
174
|
-
rescue JSONAPI::Exceptions::InvalidResource => e
|
175
|
-
@errors.concat(e.errors)
|
312
|
+
fail JSONAPI::Exceptions::InvalidResource.new(type, error_object_overrides)
|
176
313
|
end
|
177
314
|
|
178
315
|
if type_resource.nil?
|
179
|
-
|
316
|
+
fail JSONAPI::Exceptions::InvalidResource.new(type, error_object_overrides)
|
180
317
|
else
|
181
318
|
unless values.nil?
|
182
319
|
valid_fields = type_resource.fields.collect { |key| format_key(key) }
|
183
320
|
values.each do |field|
|
184
321
|
if valid_fields.include?(field)
|
185
|
-
|
322
|
+
validated_fields[type].push unformat_key(field)
|
186
323
|
else
|
187
|
-
|
324
|
+
fail JSONAPI::Exceptions::InvalidField.new(type, field, error_object_overrides)
|
188
325
|
end
|
189
326
|
end
|
190
327
|
else
|
191
|
-
|
328
|
+
fail JSONAPI::Exceptions::InvalidField.new(type, 'nil', error_object_overrides)
|
192
329
|
end
|
193
330
|
end
|
194
331
|
end
|
195
332
|
|
196
|
-
|
333
|
+
validated_fields.deep_transform_keys { |key| unformat_key(key) }
|
197
334
|
end
|
198
335
|
|
199
336
|
def check_include(resource_klass, include_parts)
|
@@ -201,211 +338,144 @@ module JSONAPI
|
|
201
338
|
|
202
339
|
relationship = resource_klass._relationship(relationship_name)
|
203
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
|
+
|
204
345
|
unless include_parts.last.empty?
|
205
|
-
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('.'))
|
206
348
|
end
|
207
349
|
else
|
208
|
-
|
209
|
-
include_parts.first).errors)
|
350
|
+
fail JSONAPI::Exceptions::InvalidInclude.new(format_key(resource_klass._type), include_parts.first)
|
210
351
|
end
|
352
|
+
true
|
211
353
|
end
|
212
354
|
|
213
|
-
def parse_include_directives(raw_include)
|
214
|
-
|
215
|
-
|
216
|
-
unless JSONAPI.configuration.allow_include
|
217
|
-
fail JSONAPI::Exceptions::ParametersNotAllowed.new([:include])
|
218
|
-
end
|
355
|
+
def parse_include_directives(resource_klass, raw_include)
|
356
|
+
raw_include ||= ''
|
219
357
|
|
220
358
|
included_resources = []
|
221
359
|
begin
|
222
|
-
included_resources += CSV.parse_line(raw_include)
|
360
|
+
included_resources += raw_include.is_a?(Array) ? raw_include : CSV.parse_line(raw_include) || []
|
223
361
|
rescue CSV::MalformedCSVError
|
224
|
-
fail JSONAPI::Exceptions::InvalidInclude.new(format_key(
|
362
|
+
fail JSONAPI::Exceptions::InvalidInclude.new(format_key(resource_klass._type), raw_include)
|
225
363
|
end
|
226
364
|
|
227
|
-
|
365
|
+
begin
|
366
|
+
result = included_resources.compact.map do |included_resource|
|
367
|
+
check_include(resource_klass, included_resource.partition('.'))
|
368
|
+
unformat_key(included_resource).to_s
|
369
|
+
end
|
228
370
|
|
229
|
-
|
230
|
-
|
231
|
-
|
371
|
+
return JSONAPI::IncludeDirectives.new(resource_klass, result)
|
372
|
+
rescue JSONAPI::Exceptions::InvalidInclude => e
|
373
|
+
@errors.concat(e.errors)
|
374
|
+
return {}
|
232
375
|
end
|
233
|
-
|
234
|
-
@include_directives = JSONAPI::IncludeDirectives.new(@resource_klass, result)
|
235
376
|
end
|
236
377
|
|
237
|
-
def parse_filters(filters)
|
238
|
-
|
378
|
+
def parse_filters(resource_klass, filters)
|
379
|
+
parsed_filters = {}
|
239
380
|
|
240
|
-
|
241
|
-
|
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]
|
242
385
|
end
|
243
386
|
|
387
|
+
return parsed_filters unless filters
|
388
|
+
|
244
389
|
unless filters.class.method_defined?(:each)
|
245
390
|
@errors.concat(JSONAPI::Exceptions::InvalidFiltersSyntax.new(filters).errors)
|
246
|
-
return
|
391
|
+
return {}
|
392
|
+
end
|
393
|
+
|
394
|
+
unless JSONAPI.configuration.allow_filter
|
395
|
+
fail JSONAPI::Exceptions::ParameterNotAllowed.new(:filter)
|
247
396
|
end
|
248
397
|
|
249
398
|
filters.each do |key, value|
|
250
399
|
filter = unformat_key(key)
|
251
|
-
if
|
252
|
-
|
400
|
+
if resource_klass._allowed_filter?(filter)
|
401
|
+
parsed_filters[filter] = value
|
253
402
|
else
|
254
|
-
|
403
|
+
fail JSONAPI::Exceptions::FilterNotAllowed.new(key)
|
255
404
|
end
|
256
405
|
end
|
257
|
-
end
|
258
406
|
|
259
|
-
|
260
|
-
@resource_klass._allowed_filters.each do |filter, opts|
|
261
|
-
next if opts[:default].nil? || !@filters[filter].nil?
|
262
|
-
@filters[filter] = opts[:default]
|
263
|
-
end
|
407
|
+
parsed_filters
|
264
408
|
end
|
265
409
|
|
266
|
-
def parse_sort_criteria(sort_criteria)
|
410
|
+
def parse_sort_criteria(resource_klass, sort_criteria)
|
267
411
|
return unless sort_criteria.present?
|
268
412
|
|
269
413
|
unless JSONAPI.configuration.allow_sort
|
270
|
-
fail JSONAPI::Exceptions::
|
414
|
+
fail JSONAPI::Exceptions::ParameterNotAllowed.new(:sort)
|
271
415
|
end
|
272
416
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
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
|
279
426
|
end
|
280
427
|
|
281
428
|
@sort_criteria = sorts.collect do |sort|
|
282
429
|
if sort.start_with?('-')
|
283
|
-
|
284
|
-
|
430
|
+
criteria = { field: unformat_key(sort[1..-1]).to_s }
|
431
|
+
criteria[:direction] = :desc
|
285
432
|
else
|
286
|
-
|
287
|
-
|
433
|
+
criteria = { field: unformat_key(sort).to_s }
|
434
|
+
criteria[:direction] = :asc
|
288
435
|
end
|
289
436
|
|
290
|
-
check_sort_criteria(
|
291
|
-
|
437
|
+
check_sort_criteria(resource_klass, criteria)
|
438
|
+
criteria
|
292
439
|
end
|
293
440
|
end
|
294
441
|
|
295
442
|
def check_sort_criteria(resource_klass, sort_criteria)
|
296
443
|
sort_field = sort_criteria[:field]
|
297
|
-
sortable_fields = resource_klass.sortable_fields(context)
|
298
444
|
|
299
|
-
unless
|
300
|
-
|
301
|
-
.new(format_key(resource_klass._type), sort_field).errors)
|
445
|
+
unless resource_klass.sortable_field?(sort_field.to_sym, context)
|
446
|
+
fail JSONAPI::Exceptions::InvalidSortCriteria.new(format_key(resource_klass._type), sort_field)
|
302
447
|
end
|
303
448
|
end
|
304
449
|
|
305
|
-
def
|
306
|
-
@operations.push JSONAPI::Operation.new(:find,
|
307
|
-
@resource_klass,
|
308
|
-
context: @context,
|
309
|
-
filters: @filters,
|
310
|
-
include_directives: @include_directives,
|
311
|
-
sort_criteria: @sort_criteria,
|
312
|
-
paginator: @paginator,
|
313
|
-
fields: @fields
|
314
|
-
)
|
315
|
-
end
|
316
|
-
|
317
|
-
def add_show_operation
|
318
|
-
@operations.push JSONAPI::Operation.new(:show,
|
319
|
-
@resource_klass,
|
320
|
-
context: @context,
|
321
|
-
id: @id,
|
322
|
-
include_directives: @include_directives,
|
323
|
-
fields: @fields
|
324
|
-
)
|
325
|
-
end
|
326
|
-
|
327
|
-
def add_show_relationship_operation(relationship_type, parent_key)
|
328
|
-
@operations.push JSONAPI::Operation.new(:show_relationship,
|
329
|
-
@resource_klass,
|
330
|
-
context: @context,
|
331
|
-
relationship_type: relationship_type,
|
332
|
-
parent_key: @resource_klass.verify_key(parent_key)
|
333
|
-
)
|
334
|
-
end
|
335
|
-
|
336
|
-
def add_show_related_resource_operation(relationship_type)
|
337
|
-
@operations.push JSONAPI::Operation.new(:show_related_resource,
|
338
|
-
@resource_klass,
|
339
|
-
context: @context,
|
340
|
-
relationship_type: relationship_type,
|
341
|
-
source_klass: @source_klass,
|
342
|
-
source_id: @source_id,
|
343
|
-
fields: @fields,
|
344
|
-
include_directives: @include_directives
|
345
|
-
)
|
346
|
-
end
|
347
|
-
|
348
|
-
def add_show_related_resources_operation(relationship_type)
|
349
|
-
@operations.push JSONAPI::Operation.new(:show_related_resources,
|
350
|
-
@resource_klass,
|
351
|
-
context: @context,
|
352
|
-
relationship_type: relationship_type,
|
353
|
-
source_klass: @source_klass,
|
354
|
-
source_id: @source_id,
|
355
|
-
filters: @source_klass.verify_filters(@filters, @context),
|
356
|
-
sort_criteria: @sort_criteria,
|
357
|
-
paginator: @paginator,
|
358
|
-
fields: @fields,
|
359
|
-
include_directives: @include_directives
|
360
|
-
)
|
361
|
-
end
|
362
|
-
|
363
|
-
def parse_add_operation(params)
|
364
|
-
fail JSONAPI::Exceptions::InvalidDataFormat unless params.respond_to?(:each_pair)
|
365
|
-
|
366
|
-
verify_type(params[:type])
|
367
|
-
|
368
|
-
data = parse_params(params, @resource_klass.creatable_fields(@context))
|
369
|
-
@operations.push JSONAPI::Operation.new(:create_resource,
|
370
|
-
@resource_klass,
|
371
|
-
context: @context,
|
372
|
-
data: data,
|
373
|
-
fields: @fields,
|
374
|
-
include_directives: @include_directives
|
375
|
-
)
|
376
|
-
rescue JSONAPI::Exceptions::Error => e
|
377
|
-
@errors.concat(e.errors)
|
378
|
-
end
|
379
|
-
|
380
|
-
def verify_type(type)
|
450
|
+
def verify_type(type, resource_klass)
|
381
451
|
if type.nil?
|
382
452
|
fail JSONAPI::Exceptions::ParameterMissing.new(:type)
|
383
|
-
elsif unformat_key(type).to_sym !=
|
384
|
-
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)
|
385
455
|
end
|
386
456
|
end
|
387
457
|
|
388
458
|
def parse_to_one_links_object(raw)
|
389
459
|
if raw.nil?
|
390
460
|
return {
|
391
|
-
|
392
|
-
|
461
|
+
type: nil,
|
462
|
+
id: nil
|
393
463
|
}
|
394
464
|
end
|
395
465
|
|
396
466
|
if !(raw.is_a?(Hash) || raw.is_a?(ActionController::Parameters)) ||
|
397
|
-
|
398
|
-
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)
|
399
469
|
end
|
400
470
|
|
401
471
|
{
|
402
|
-
|
403
|
-
|
472
|
+
type: unformat_key(raw['type']).to_s,
|
473
|
+
id: raw['id']
|
404
474
|
}
|
405
475
|
end
|
406
476
|
|
407
477
|
def parse_to_many_links_object(raw)
|
408
|
-
fail JSONAPI::Exceptions::InvalidLinksObject.new if raw.nil?
|
478
|
+
fail JSONAPI::Exceptions::InvalidLinksObject.new(error_object_overrides) if raw.nil?
|
409
479
|
|
410
480
|
links_object = {}
|
411
481
|
if raw.is_a?(Array)
|
@@ -415,12 +485,12 @@ module JSONAPI
|
|
415
485
|
links_object[link_object[:type]].push(link_object[:id])
|
416
486
|
end
|
417
487
|
else
|
418
|
-
fail JSONAPI::Exceptions::InvalidLinksObject.new
|
488
|
+
fail JSONAPI::Exceptions::InvalidLinksObject.new(error_object_overrides)
|
419
489
|
end
|
420
490
|
links_object
|
421
491
|
end
|
422
492
|
|
423
|
-
def parse_params(params, allowed_fields)
|
493
|
+
def parse_params(resource_klass, params, allowed_fields)
|
424
494
|
verify_permitted_params(params, allowed_fields)
|
425
495
|
|
426
496
|
checked_attributes = {}
|
@@ -429,37 +499,37 @@ module JSONAPI
|
|
429
499
|
|
430
500
|
params.each do |key, value|
|
431
501
|
case key.to_s
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
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
|
442
513
|
end
|
443
514
|
end
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
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
|
452
522
|
end
|
453
523
|
end
|
454
524
|
|
455
525
|
return {
|
456
|
-
|
457
|
-
|
458
|
-
|
526
|
+
'attributes' => checked_attributes,
|
527
|
+
'to_one' => checked_to_one_relationships,
|
528
|
+
'to_many' => checked_to_many_relationships
|
459
529
|
}.deep_transform_keys { |key| unformat_key(key) }
|
460
530
|
end
|
461
531
|
|
462
|
-
def parse_to_one_relationship(link_value, relationship)
|
532
|
+
def parse_to_one_relationship(resource_klass, link_value, relationship)
|
463
533
|
if link_value.nil?
|
464
534
|
linkage = nil
|
465
535
|
else
|
@@ -468,12 +538,12 @@ module JSONAPI
|
|
468
538
|
|
469
539
|
links_object = parse_to_one_links_object(linkage)
|
470
540
|
if !relationship.polymorphic? && links_object[:type] && (links_object[:type].to_s != relationship.type.to_s)
|
471
|
-
fail JSONAPI::Exceptions::TypeMismatch.new(links_object[:type])
|
541
|
+
fail JSONAPI::Exceptions::TypeMismatch.new(links_object[:type], error_object_overrides)
|
472
542
|
end
|
473
543
|
|
474
544
|
unless links_object[:id].nil?
|
475
|
-
resource =
|
476
|
-
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)
|
477
547
|
relationship_id = relationship_resource.verify_key(links_object[:id], @context)
|
478
548
|
if relationship.polymorphic?
|
479
549
|
{ id: relationship_id, type: unformat_key(links_object[:type].to_s) }
|
@@ -485,37 +555,54 @@ module JSONAPI
|
|
485
555
|
end
|
486
556
|
end
|
487
557
|
|
488
|
-
def parse_to_many_relationship(link_value, relationship, &add_result)
|
489
|
-
if link_value.is_a?(
|
490
|
-
linkage = []
|
491
|
-
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))
|
492
560
|
linkage = link_value[:data]
|
493
561
|
else
|
494
|
-
fail JSONAPI::Exceptions::InvalidLinksObject.new
|
562
|
+
fail JSONAPI::Exceptions::InvalidLinksObject.new(error_object_overrides)
|
495
563
|
end
|
496
564
|
|
497
565
|
links_object = parse_to_many_links_object(linkage)
|
498
566
|
|
499
|
-
# Since we do not yet support polymorphic to_many relationships we will raise an error if the type does not match the
|
500
|
-
# relationship's type.
|
501
|
-
# ToDo: Support Polymorphic relationships
|
502
|
-
|
503
567
|
if links_object.length == 0
|
504
568
|
add_result.call([])
|
505
569
|
else
|
506
|
-
if
|
507
|
-
|
508
|
-
|
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
|
509
589
|
|
510
|
-
|
511
|
-
|
512
|
-
|
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)
|
513
600
|
end
|
514
601
|
end
|
515
602
|
end
|
516
603
|
|
517
|
-
def unformat_value(attribute, value)
|
518
|
-
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])
|
519
606
|
value_formatter.unformat(value)
|
520
607
|
end
|
521
608
|
|
@@ -525,68 +612,76 @@ module JSONAPI
|
|
525
612
|
|
526
613
|
params.each do |key, value|
|
527
614
|
case key.to_s
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
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
|
534
624
|
end
|
535
625
|
end
|
536
|
-
|
537
|
-
|
538
|
-
|
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
|
543
635
|
end
|
544
636
|
end
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
637
|
+
when 'type'
|
638
|
+
when 'id'
|
639
|
+
unless formatted_allowed_fields.include?(:id)
|
640
|
+
if JSONAPI.configuration.raise_if_parameters_not_allowed
|
641
|
+
fail JSONAPI::Exceptions::ParameterNotAllowed.new(:id, error_object_overrides)
|
642
|
+
else
|
643
|
+
params_not_allowed.push(:id)
|
644
|
+
params.delete :id
|
645
|
+
end
|
646
|
+
end
|
647
|
+
else
|
648
|
+
if JSONAPI.configuration.raise_if_parameters_not_allowed
|
649
|
+
fail JSONAPI::Exceptions::ParameterNotAllowed.new(key, error_object_overrides)
|
650
|
+
else
|
651
|
+
params_not_allowed.push(key)
|
652
|
+
params.delete key
|
552
653
|
end
|
553
|
-
end
|
554
|
-
else
|
555
|
-
params_not_allowed.push(key)
|
556
654
|
end
|
557
655
|
end
|
558
656
|
|
559
657
|
if params_not_allowed.length > 0
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
JSONAPI::Warning.new(code: JSONAPI::PARAM_NOT_ALLOWED,
|
565
|
-
title: 'Param not allowed',
|
566
|
-
detail: "#{key} is not allowed.")
|
567
|
-
end
|
568
|
-
self.warnings.concat(params_not_allowed_warnings)
|
658
|
+
params_not_allowed_warnings = params_not_allowed.map do |param|
|
659
|
+
JSONAPI::Warning.new(code: JSONAPI::PARAM_NOT_ALLOWED,
|
660
|
+
title: 'Param not allowed',
|
661
|
+
detail: "#{param} is not allowed.")
|
569
662
|
end
|
663
|
+
self.warnings.concat(params_not_allowed_warnings)
|
570
664
|
end
|
571
665
|
end
|
572
666
|
|
573
|
-
def parse_add_relationship_operation(verified_params, relationship, parent_key)
|
667
|
+
def parse_add_relationship_operation(resource_klass, verified_params, relationship, parent_key)
|
574
668
|
if relationship.is_a?(JSONAPI::Relationship::ToMany)
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
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]
|
581
676
|
)
|
582
677
|
end
|
583
678
|
end
|
584
679
|
|
585
|
-
def parse_update_relationship_operation(verified_params, relationship, parent_key)
|
680
|
+
def parse_update_relationship_operation(resource_klass, verified_params, relationship, parent_key)
|
586
681
|
options = {
|
587
|
-
|
588
|
-
|
589
|
-
|
682
|
+
context: @context,
|
683
|
+
resource_id: parent_key,
|
684
|
+
relationship_type: relationship.name
|
590
685
|
}
|
591
686
|
|
592
687
|
if relationship.is_a?(JSONAPI::Relationship::ToOne)
|
@@ -607,62 +702,30 @@ module JSONAPI
|
|
607
702
|
operation_type = :replace_to_many_relationships
|
608
703
|
end
|
609
704
|
|
610
|
-
|
705
|
+
JSONAPI::Operation.new(operation_type, resource_klass, options)
|
611
706
|
end
|
612
707
|
|
613
|
-
def
|
614
|
-
fail JSONAPI::Exceptions::InvalidDataFormat unless data.respond_to?(:each_pair)
|
615
|
-
|
616
|
-
fail JSONAPI::Exceptions::MissingKey.new if data[:id].nil?
|
617
|
-
|
618
|
-
key = data[:id].to_s
|
619
|
-
if id_key_presence_check_required && !keys.include?(key)
|
620
|
-
fail JSONAPI::Exceptions::KeyNotIncludedInURL.new(key)
|
621
|
-
end
|
622
|
-
|
623
|
-
data.delete(:id) unless keys.include?(:id)
|
624
|
-
|
625
|
-
verify_type(data[:type])
|
626
|
-
|
627
|
-
@operations.push JSONAPI::Operation.new(:replace_fields,
|
628
|
-
@resource_klass,
|
629
|
-
context: @context,
|
630
|
-
resource_id: key,
|
631
|
-
data: parse_params(data, @resource_klass.updatable_fields(@context)),
|
632
|
-
fields: @fields,
|
633
|
-
include_directives: @include_directives
|
634
|
-
)
|
635
|
-
end
|
636
|
-
|
637
|
-
def parse_replace_operation(data, keys)
|
638
|
-
parse_single_replace_operation(data, [keys], id_key_presence_check_required: keys.present?)
|
639
|
-
rescue JSONAPI::Exceptions::Error => e
|
640
|
-
@errors.concat(e.errors)
|
641
|
-
end
|
642
|
-
|
643
|
-
def parse_remove_operation(params)
|
644
|
-
@operations.push JSONAPI::Operation.new(:remove_resource,
|
645
|
-
@resource_klass,
|
646
|
-
context: @context,
|
647
|
-
resource_id: @resource_klass.verify_key(params.require(:id), context))
|
648
|
-
rescue JSONAPI::Exceptions::Error => e
|
649
|
-
@errors.concat(e.errors)
|
650
|
-
end
|
651
|
-
|
652
|
-
def parse_remove_relationship_operation(params, relationship, parent_key)
|
708
|
+
def parse_remove_relationship_operation(resource_klass, params, relationship, parent_key)
|
653
709
|
operation_base_args = [resource_klass].push(
|
654
|
-
|
655
|
-
|
656
|
-
|
710
|
+
context: @context,
|
711
|
+
resource_id: parent_key,
|
712
|
+
relationship_type: relationship.name
|
657
713
|
)
|
658
714
|
|
659
715
|
if relationship.is_a?(JSONAPI::Relationship::ToMany)
|
660
716
|
operation_args = operation_base_args.dup
|
661
717
|
keys = params[:to_many].values[0]
|
662
718
|
operation_args[1] = operation_args[1].merge(associated_keys: keys)
|
663
|
-
|
719
|
+
JSONAPI::Operation.new(:remove_to_many_relationships, *operation_args)
|
664
720
|
else
|
665
|
-
|
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
|
666
729
|
end
|
667
730
|
end
|
668
731
|
|