jsonapi-resources 0.1.1 → 0.2.0

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.
@@ -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