jsonapi-resources 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,13 @@
1
1
  require 'jsonapi/resource_for'
2
2
  require 'jsonapi/operation'
3
+ require 'jsonapi/paginator'
3
4
 
4
5
  module JSONAPI
5
6
  class Request
6
7
  include ResourceFor
7
8
 
8
- attr_accessor :fields, :include, :filters, :sort_params, :errors, :operations, :resource_klass, :context
9
+ attr_accessor :fields, :include, :filters, :sort_criteria, :errors, :operations,
10
+ :resource_klass, :context, :paginator, :source_klass, :source_id
9
11
 
10
12
  def initialize(params = nil, options = {})
11
13
  @context = options.fetch(:context, nil)
@@ -15,6 +17,9 @@ module JSONAPI
15
17
  @fields = {}
16
18
  @include = []
17
19
  @filters = {}
20
+ @sort_criteria = []
21
+ @source_klass = nil
22
+ @source_id = nil
18
23
 
19
24
  setup(params) if params
20
25
  end
@@ -25,71 +30,90 @@ module JSONAPI
25
30
  unless params.nil?
26
31
  case params[:action]
27
32
  when 'index'
28
- parse_fields(params)
29
- parse_include(params)
30
- parse_filters(params)
31
- parse_sort_params(params)
32
- when 'show_associations'
33
+ parse_fields(params[:fields])
34
+ parse_include(params[:include])
35
+ parse_filters(params[:filter])
36
+ parse_sort_criteria(params[:sort])
37
+ parse_pagination(params[:page])
38
+ when 'get_related_resource', 'get_related_resources'
39
+ @source_klass = self.class.resource_for(params.require(:source))
40
+ @source_id = params.require(@source_klass._as_parent_key)
41
+ parse_fields(params[:fields])
42
+ parse_include(params[:include])
43
+ parse_filters(params[:filter])
44
+ parse_sort_criteria(params[:sort])
45
+ parse_pagination(params[:page])
33
46
  when 'show'
34
- parse_fields(params)
35
- parse_include(params)
47
+ parse_fields(params[:fields])
48
+ parse_include(params[:include])
36
49
  when 'create'
37
- parse_fields(params)
38
- parse_include(params)
39
- parse_add_operation(params)
50
+ parse_fields(params[:fields])
51
+ parse_include(params[:include])
52
+ parse_add_operation(params.require(:data))
40
53
  when 'create_association'
41
- parse_add_association_operation(params)
54
+ parse_add_association_operation(params.require(:data),
55
+ params.require(:association),
56
+ params.require(@resource_klass._as_parent_key))
42
57
  when 'update_association'
43
- parse_update_association_operation(params)
58
+ parse_update_association_operation(params.require(:data),
59
+ params.require(:association),
60
+ params.require(@resource_klass._as_parent_key))
44
61
  when 'update'
45
- parse_fields(params)
46
- parse_include(params)
47
- parse_replace_operation(params)
62
+ parse_fields(params[:fields])
63
+ parse_include(params[:include])
64
+ parse_replace_operation(params.require(:data), params.require(@resource_klass._primary_key))
48
65
  when 'destroy'
49
66
  parse_remove_operation(params)
50
67
  when 'destroy_association'
51
68
  parse_remove_association_operation(params)
52
69
  end
53
70
  end
71
+ rescue ActionController::ParameterMissing => e
72
+ @errors.concat(JSONAPI::Exceptions::ParameterMissing.new(e.param).errors)
54
73
  end
55
74
 
56
- def parse_fields(params)
57
- fields = {}
75
+ def parse_pagination(page)
76
+ paginator_name = @resource_klass._paginator
77
+ @paginator = JSONAPI::Paginator.paginator_for(paginator_name).new(page) unless paginator_name == :none
78
+ rescue JSONAPI::Exceptions::Error => e
79
+ @errors.concat(e.errors)
80
+ end
81
+
82
+ def parse_fields(fields)
83
+ return if fields.nil?
84
+
85
+ extracted_fields = {}
58
86
 
59
87
  # Extract the fields for each type from the fields parameters
60
- unless params[:fields].nil?
61
- if params[:fields].is_a?(String)
62
- value = params[:fields]
88
+ if fields.is_a?(String)
89
+ resource_fields = fields.split(',') unless fields.empty?
90
+ type = @resource_klass._type
91
+ extracted_fields[type] = resource_fields
92
+ elsif fields.is_a?(ActionController::Parameters)
93
+ fields.each do |field, value|
63
94
  resource_fields = value.split(',') unless value.nil? || value.empty?
64
- type = @resource_klass._type
65
- fields[type] = resource_fields
66
- elsif params[:fields].is_a?(ActionController::Parameters)
67
- params[:fields].each do |param, value|
68
- resource_fields = value.split(',') unless value.nil? || value.empty?
69
- type = param
70
- fields[type] = resource_fields
71
- end
95
+ extracted_fields[field] = resource_fields
72
96
  end
73
97
  end
74
98
 
75
99
  # Validate the fields
76
- fields.each do |type, values|
100
+ extracted_fields.each do |type, values|
77
101
  underscored_type = unformat_key(type)
78
- fields[type] = []
102
+ extracted_fields[type] = []
79
103
  begin
80
104
  type_resource = self.class.resource_for(@resource_klass.module_path + underscored_type.to_s)
81
105
  rescue NameError
82
106
  @errors.concat(JSONAPI::Exceptions::InvalidResource.new(type).errors)
83
107
  end
84
- if type_resource.nil? || !(@resource_klass._type == underscored_type ||
85
- @resource_klass._has_association?(underscored_type))
86
- @errors.concat(JSONAPI::Exceptions::InvalidResource.new(type).errors)
108
+ if type_resource.nil? || !(@resource_klass._type == underscored_type ||
109
+ @resource_klass._has_association?(underscored_type))
110
+ @errors.concat(JSONAPI::Exceptions::InvalidResource.new(type).errors)
87
111
  else
88
112
  unless values.nil?
89
- valid_fields = type_resource.fields.collect {|key| format_key(key)}
113
+ valid_fields = type_resource.fields.collect { |key| format_key(key) }
90
114
  values.each do |field|
91
115
  if valid_fields.include?(field)
92
- fields[type].push unformat_key(field)
116
+ extracted_fields[type].push unformat_key(field)
93
117
  else
94
118
  @errors.concat(JSONAPI::Exceptions::InvalidField.new(type, field).errors)
95
119
  end
@@ -100,7 +124,7 @@ module JSONAPI
100
124
  end
101
125
  end
102
126
 
103
- @fields = fields.deep_transform_keys{ |key| unformat_key(key) }
127
+ @fields = extracted_fields.deep_transform_keys { |key| unformat_key(key) }
104
128
  end
105
129
 
106
130
  def check_include(resource_klass, include_parts)
@@ -113,100 +137,137 @@ module JSONAPI
113
137
  end
114
138
  else
115
139
  @errors.concat(JSONAPI::Exceptions::InvalidInclude.new(format_key(resource_klass._type),
116
- include_parts.first, ).errors)
140
+ include_parts.first,).errors)
117
141
  end
118
142
  end
119
143
 
120
- def parse_include(params)
121
- included_resources_raw = CSV.parse_line(params[:include]) unless params[:include].nil? || params[:include].empty?
144
+ def parse_include(include)
145
+ return if include.nil?
146
+
147
+ included_resources = CSV.parse_line(include)
148
+ return if included_resources.nil?
149
+
122
150
  @include = []
123
- return if included_resources_raw.nil?
124
- included_resources_raw.each do |include|
125
- check_include(@resource_klass, include.partition('.'))
126
- @include.push(unformat_key(include).to_s)
151
+ included_resources.each do |included_resource|
152
+ check_include(@resource_klass, included_resource.partition('.'))
153
+ @include.push(unformat_key(included_resource).to_s)
127
154
  end
128
155
  end
129
156
 
130
- def parse_filters(params)
131
- # Coerce :ids -> :id
132
- if params[:ids]
133
- params[:id] = params[:ids]
134
- params.delete(:ids)
135
- end
136
-
137
- filters = {}
138
- params.each do |key, value|
139
- filter = key.to_sym
140
-
141
- # Ignore non-filter parameters
142
- next if JSONAPI.configuration.allowed_request_params.include?(filter)
143
-
157
+ def parse_filters(filters)
158
+ return unless filters
159
+ @filters = {}
160
+ filters.each do |key, value|
144
161
  filter = unformat_key(key).to_sym
145
162
  if @resource_klass._allowed_filter?(filter)
146
- filters[filter] = value
163
+ @filters[filter] = value
147
164
  else
148
165
  @errors.concat(JSONAPI::Exceptions::FilterNotAllowed.new(filter).errors)
149
166
  end
150
167
  end
151
- @filters = filters
152
168
  end
153
169
 
154
- def parse_sort_params(params)
155
- @sort_params = if params[:sort].present?
156
- CSV.parse_line(params[:sort]).collect do |sort_param|
157
- # A parameter name may not start with a dash
158
- # We need to preserve the dash as the sort direction before we unformat the string
159
- if sort_param.start_with?('-')
160
- unformatted_sort_param = unformat_key(sort_param[1..-1]).to_s
161
- unformatted_sort_param.prepend('-')
162
- else
163
- unformatted_sort_param = unformat_key(sort_param).to_s
164
- end
170
+ def parse_sort_criteria(sort_criteria)
171
+ return unless sort_criteria
165
172
 
166
- check_sort_param(@resource_klass, unformatted_sort_param)
167
- unformatted_sort_param
173
+ @sort_criteria = CSV.parse_line(sort_criteria).collect do |sort|
174
+ sort_criteria = {field: unformat_key(sort[1..-1]).to_s}
175
+ if sort.start_with?('+')
176
+ sort_criteria[:direction] = :asc
177
+ elsif sort.start_with?('-')
178
+ sort_criteria[:direction] = :desc
179
+ else
180
+ @errors.concat(JSONAPI::Exceptions::InvalidSortFormat
181
+ .new(format_key(resource_klass._type), sort).errors)
168
182
  end
169
- else
170
- []
183
+
184
+ check_sort_criteria(@resource_klass, sort_criteria)
185
+ sort_criteria
171
186
  end
172
187
  end
173
188
 
174
- def check_sort_param(resource_klass, sort_param)
175
- sort_param = sort_param.sub(/\A-/, '')
189
+ def check_sort_criteria(resource_klass, sort_criteria)
190
+ sort_field = sort_criteria[:field]
176
191
  sortable_fields = resource_klass.sortable_fields(context)
177
192
 
178
- unless sortable_fields.include? sort_param.to_sym
179
- @errors.concat(JSONAPI::Exceptions::InvalidSortParam
180
- .new(format_key(resource_klass._type), sort_param).errors)
193
+ unless sortable_fields.include? sort_field.to_sym
194
+ @errors.concat(JSONAPI::Exceptions::InvalidSortCriteria
195
+ .new(format_key(resource_klass._type), sort_field).errors)
181
196
  end
182
197
  end
183
198
 
184
- def parse_add_operation(params)
185
- object_params_raw = params.require(format_key(@resource_klass._type))
186
-
187
- if object_params_raw.is_a?(Array)
188
- object_params_raw.each do |p|
199
+ def parse_add_operation(data)
200
+ if data.is_a?(Array)
201
+ data.each do |p|
189
202
  @operations.push JSONAPI::CreateResourceOperation.new(@resource_klass,
190
- parse_params(p, @resource_klass.createable_fields(@context)))
203
+ parse_params(verify_and_remove_type(p),
204
+ @resource_klass.createable_fields(@context)))
191
205
  end
192
206
  else
193
207
  @operations.push JSONAPI::CreateResourceOperation.new(@resource_klass,
194
- parse_params(object_params_raw, @resource_klass.createable_fields(@context)))
208
+ parse_params(verify_and_remove_type(data),
209
+ @resource_klass.createable_fields(@context)))
195
210
  end
196
- rescue ActionController::ParameterMissing => e
197
- @errors.concat(JSONAPI::Exceptions::ParameterMissing.new(e.param).errors)
198
211
  rescue JSONAPI::Exceptions::Error => e
199
212
  @errors.concat(e.errors)
200
213
  end
201
214
 
202
- def parse_params(params, allowed_fields)
203
- # push links into top level param list with attributes in order to check for invalid params
204
- if params[:links]
205
- params[:links].each do |link, value|
206
- params[link] = value
215
+ def verify_and_remove_type(params)
216
+ #remove type and verify it matches the resource
217
+ if params[:type] == @resource_klass._type.to_s
218
+ params.delete(:type)
219
+ else
220
+ if params[:type].nil?
221
+ raise JSONAPI::Exceptions::ParameterMissing.new(:type)
222
+ else
223
+ raise JSONAPI::Exceptions::InvalidResource.new(params[:type])
224
+ end
225
+ end
226
+ params
227
+ end
228
+
229
+ def parse_has_one_links_object(raw)
230
+ if raw.nil?
231
+ return {
232
+ type: nil,
233
+ id: nil
234
+ }
235
+ end
236
+
237
+ if !raw.is_a?(Hash) || raw.length != 2 || !(raw.has_key?('type') && raw.has_key?('id'))
238
+ raise JSONAPI::Exceptions::InvalidLinksObject.new(raw)
239
+ end
240
+
241
+ {
242
+ type: raw['type'],
243
+ id: raw['id']
244
+ }
245
+ end
246
+
247
+ def parse_has_many_links_object(raw)
248
+ if raw.nil?
249
+ raise JSONAPI::Exceptions::InvalidLinksObject.new(raw)
250
+ end
251
+
252
+ links_object = {}
253
+ if raw.is_a?(Hash)
254
+ if raw.length != 2 || !(raw.has_key?('type') && raw.has_key?('ids')) || !(raw['ids'].is_a?(Array))
255
+ raise JSONAPI::Exceptions::InvalidLinksObject.new(raw)
207
256
  end
208
- params.delete(:links)
257
+ links_object[raw['type']] = raw['ids']
258
+ elsif raw.is_a?(Array)
259
+ raw.each do |link|
260
+ link_object = parse_has_one_links_object(link)
261
+ links_object[link_object[:type]] ||= []
262
+ links_object[link_object[:type]].push(link_object[:id])
263
+ end
264
+ else
265
+ raise JSONAPI::Exceptions::InvalidLinksObject.new(raw)
209
266
  end
267
+ links_object
268
+ end
269
+
270
+ def parse_params(params, allowed_fields)
210
271
  verify_permitted_params(params, allowed_fields)
211
272
 
212
273
  checked_attributes = {}
@@ -214,21 +275,54 @@ module JSONAPI
214
275
  checked_has_many_associations = {}
215
276
 
216
277
  params.each do |key, value|
217
- param = unformat_key(key)
278
+ if key == 'links' || key == :links
279
+ value.each do |link_key, link_value|
280
+ param = unformat_key(link_key)
281
+
282
+ association = @resource_klass._association(param)
283
+
284
+ if association.is_a?(JSONAPI::Association::HasOne)
285
+ links_object = parse_has_one_links_object(link_value)
286
+ # Since we do not yet support polymorphic associations we will raise an error if the type does not match the
287
+ # association's type.
288
+ # ToDo: Support Polymorphic associations
289
+ if links_object[:type] && (links_object[:type] != association.type.to_s)
290
+ raise JSONAPI::Exceptions::TypeMismatch.new(links_object[:type])
291
+ end
218
292
 
219
- association = @resource_klass._association(param)
293
+ unless links_object[:id].nil?
294
+ association_resource = @resource_klass.resource_for(@resource_klass.module_path + links_object[:type])
295
+ checked_has_one_associations[param] = association_resource.verify_key(links_object[:id], @context)
296
+ else
297
+ checked_has_one_associations[param] = nil
298
+ end
299
+ elsif association.is_a?(JSONAPI::Association::HasMany)
300
+ links_object = parse_has_many_links_object(link_value)
220
301
 
221
- if association.is_a?(JSONAPI::Association::HasOne)
222
- checked_has_one_associations[param] = @resource_klass.resource_for(@resource_klass.module_path + association.type.to_s).verify_key(value, @context)
223
- elsif association.is_a?(JSONAPI::Association::HasMany)
224
- keys = []
225
- if value.is_a?(Array)
226
- keys = @resource_klass.resource_for(@resource_klass.module_path + association.type.to_s).verify_keys(value, @context)
227
- else
228
- keys.push(@resource_klass.resource_for(@resource_klass.module_path + association.type.to_s).verify_key(value, @context))
302
+ # Since we do not yet support polymorphic associations we will raise an error if the type does not match the
303
+ # association's type.
304
+ # ToDo: Support Polymorphic associations
305
+
306
+ if links_object.length == 0
307
+ checked_has_many_associations[param] = []
308
+ else
309
+ if links_object.length > 1 || !links_object.has_key?(association.type.to_s)
310
+ raise JSONAPI::Exceptions::TypeMismatch.new(links_object[:type])
311
+ end
312
+
313
+ links_object.each_pair do |type, keys|
314
+ association_resource = @resource_klass.resource_for(@resource_klass.module_path + type)
315
+ checked_has_many_associations[param] = association_resource.verify_keys(keys, @context)
316
+ end
317
+ end
318
+ else
319
+ # :nocov:
320
+ raise JSONAPI::Exceptions::InvalidLinksObject.new(key)
321
+ # :nocov:
322
+ end
229
323
  end
230
- checked_has_many_associations[param] = keys
231
324
  else
325
+ param = unformat_key(key)
232
326
  checked_attributes[param] = unformat_value(param, value)
233
327
  end
234
328
  end
@@ -237,7 +331,7 @@ module JSONAPI
237
331
  'attributes' => checked_attributes,
238
332
  'has_one' => checked_has_one_associations,
239
333
  'has_many' => checked_has_many_associations
240
- }.deep_transform_keys{ |key| unformat_key(key) }
334
+ }.deep_transform_keys { |key| unformat_key(key) }
241
335
  end
242
336
 
243
337
  def unformat_value(attribute, value)
@@ -246,67 +340,49 @@ module JSONAPI
246
340
  end
247
341
 
248
342
  def verify_permitted_params(params, allowed_fields)
249
- formatted_allowed_fields = allowed_fields.collect {|field| format_key(field).to_sym}
343
+ formatted_allowed_fields = allowed_fields.collect { |field| format_key(field).to_sym }
250
344
  params_not_allowed = []
251
- params.keys.each do |key|
252
- params_not_allowed.push(key) unless formatted_allowed_fields.include?(key.to_sym)
345
+ params.each do |key, value|
346
+ if key == 'links' || key == :links
347
+ value.each_key do |links_key|
348
+ params_not_allowed.push(links_key) unless formatted_allowed_fields.include?(links_key.to_sym)
349
+ end
350
+ else
351
+ params_not_allowed.push(key) unless formatted_allowed_fields.include?(key.to_sym)
352
+ end
253
353
  end
254
354
  raise JSONAPI::Exceptions::ParametersNotAllowed.new(params_not_allowed) if params_not_allowed.length > 0
255
355
  end
256
356
 
257
- def parse_add_association_operation(params)
258
- association_type = params[:association]
259
-
260
- parent_key = params[resource_klass._as_parent_key]
261
-
357
+ def parse_add_association_operation(data, association_type, parent_key)
262
358
  association = resource_klass._association(association_type)
263
359
 
264
- if association.is_a?(JSONAPI::Association::HasOne)
265
- plural_association_type = association_type.pluralize
266
-
267
- if params[plural_association_type].nil?
268
- raise ActionController::ParameterMissing.new(plural_association_type)
269
- end
270
-
271
- object_params = {links: {association_type => params[plural_association_type]}}
272
- verified_param_set = parse_params(object_params, @resource_klass.updateable_fields(@context))
273
-
274
- @operations.push JSONAPI::CreateHasOneAssociationOperation.new(resource_klass,
275
- parent_key,
276
- association_type,
277
- verified_param_set[:has_one].values[0])
278
- else
279
- if params[association_type].nil?
280
- raise ActionController::ParameterMissing.new(association_type)
281
- end
360
+ if association.is_a?(JSONAPI::Association::HasMany)
361
+ ids = data.require(:ids)
362
+ type = data.require(:type)
282
363
 
283
- object_params = {links: {association_type => params[association_type]}}
364
+ object_params = {links: {association.name => {'type' => type, 'ids' => ids}}}
284
365
  verified_param_set = parse_params(object_params, @resource_klass.updateable_fields(@context))
285
366
 
286
367
  @operations.push JSONAPI::CreateHasManyAssociationOperation.new(resource_klass,
287
368
  parent_key,
288
369
  association_type,
289
370
  verified_param_set[:has_many].values[0])
371
+ else
372
+ # :nocov:
373
+ @errors.concat(JSONAPI::Exceptions::InvalidLinksObject.new(:data).errors)
374
+ # :nocov:
290
375
  end
291
376
  rescue ActionController::ParameterMissing => e
292
377
  @errors.concat(JSONAPI::Exceptions::ParameterMissing.new(e.param).errors)
293
378
  end
294
379
 
295
- def parse_update_association_operation(params)
296
- association_type = params[:association]
297
-
298
- parent_key = params[resource_klass._as_parent_key]
299
-
380
+ def parse_update_association_operation(data, association_type, parent_key)
300
381
  association = resource_klass._association(association_type)
301
382
 
302
383
  if association.is_a?(JSONAPI::Association::HasOne)
303
- plural_association_type = association_type.pluralize
304
-
305
- if params[plural_association_type].nil?
306
- raise ActionController::ParameterMissing.new(plural_association_type)
307
- end
384
+ object_params = {links: {association.name => data}}
308
385
 
309
- object_params = {links: {association_type => params[plural_association_type]}}
310
386
  verified_param_set = parse_params(object_params, @resource_klass.updateable_fields(@context))
311
387
 
312
388
  @operations.push JSONAPI::ReplaceHasOneAssociationOperation.new(resource_klass,
@@ -314,11 +390,7 @@ module JSONAPI
314
390
  association_type,
315
391
  verified_param_set[:has_one].values[0])
316
392
  else
317
- if params[association_type].nil?
318
- raise ActionController::ParameterMissing.new(association_type)
319
- end
320
-
321
- object_params = {links: {association_type => params[association_type]}}
393
+ object_params = {links: {association.name => data}}
322
394
  verified_param_set = parse_params(object_params, @resource_klass.updateable_fields(@context))
323
395
 
324
396
  @operations.push JSONAPI::ReplaceHasManyAssociationOperation.new(resource_klass,
@@ -326,43 +398,46 @@ module JSONAPI
326
398
  association_type,
327
399
  verified_param_set[:has_many].values[0])
328
400
  end
329
- rescue ActionController::ParameterMissing => e
330
- @errors.concat(JSONAPI::Exceptions::ParameterMissing.new(e.param).errors)
331
401
  end
332
402
 
333
- def parse_replace_operation(params)
334
- object_params_raw = params.require(format_key(@resource_klass._type))
403
+ def parse_single_replace_operation(data, keys)
404
+ if data[@resource_klass._primary_key].nil?
405
+ raise JSONAPI::Exceptions::MissingKey.new
406
+ end
407
+
408
+ type = data[:type]
409
+ if type.nil? || type != @resource_klass._type.to_s
410
+ raise JSONAPI::Exceptions::ParameterMissing.new(:type)
411
+ end
412
+
413
+ key = data[@resource_klass._primary_key]
414
+ if !keys.include?(key)
415
+ raise JSONAPI::Exceptions::KeyNotIncludedInURL.new(key)
416
+ end
417
+
418
+ if !keys.include?(@resource_klass._primary_key)
419
+ data.delete(:id)
420
+ end
421
+
422
+ @operations.push(JSONAPI::ReplaceFieldsOperation.new(@resource_klass,
423
+ key,
424
+ parse_params(verify_and_remove_type(data),
425
+ @resource_klass.updateable_fields(@context))))
426
+ end
335
427
 
336
- keys = params[@resource_klass._primary_key]
337
- if object_params_raw.is_a?(Array)
338
- if keys.count != object_params_raw.count
428
+ def parse_replace_operation(data, keys)
429
+ if data.is_a?(Array)
430
+ if keys.count != data.count
339
431
  raise JSONAPI::Exceptions::CountMismatch
340
432
  end
341
433
 
342
- object_params_raw.each do |object_params|
343
- if object_params[@resource_klass._primary_key].nil?
344
- raise JSONAPI::Exceptions::MissingKey.new
345
- end
346
-
347
- if !keys.include?(object_params[@resource_klass._primary_key])
348
- raise JSONAPI::Exceptions::KeyNotIncludedInURL.new(object_params[@resource_klass._primary_key])
349
- end
350
- @operations.push JSONAPI::ReplaceFieldsOperation.new(@resource_klass,
351
- object_params[@resource_klass._primary_key],
352
- parse_params(object_params, @resource_klass.updateable_fields(@context)))
434
+ data.each do |object_params|
435
+ parse_single_replace_operation(object_params, keys)
353
436
  end
354
437
  else
355
- if !object_params_raw[@resource_klass._primary_key].nil? && keys != object_params_raw[@resource_klass._primary_key]
356
- raise JSONAPI::Exceptions::KeyNotIncludedInURL.new(object_params_raw[@resource_klass._primary_key])
357
- end
358
-
359
- @operations.push JSONAPI::ReplaceFieldsOperation.new(@resource_klass,
360
- params[@resource_klass._primary_key],
361
- parse_params(object_params_raw, @resource_klass.updateable_fields(@context)))
438
+ parse_single_replace_operation(data, [keys])
362
439
  end
363
440
 
364
- rescue ActionController::ParameterMissing => e
365
- @errors.concat(JSONAPI::Exceptions::ParameterMissing.new(e.param).errors)
366
441
  rescue JSONAPI::Exceptions::Error => e
367
442
  @errors.concat(e.errors)
368
443
  end
@@ -389,14 +464,14 @@ module JSONAPI
389
464
  keys = parse_key_array(params[:keys])
390
465
  keys.each do |key|
391
466
  @operations.push JSONAPI::RemoveHasManyAssociationOperation.new(resource_klass,
392
- parent_key,
393
- association_type,
394
- key)
467
+ parent_key,
468
+ association_type,
469
+ key)
395
470
  end
396
471
  else
397
472
  @operations.push JSONAPI::RemoveHasOneAssociationOperation.new(resource_klass,
398
- parent_key,
399
- association_type)
473
+ parent_key,
474
+ association_type)
400
475
  end
401
476
  end
402
477