restful_json 3.4.2 → 4.0.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.
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ task :default do |t|
9
9
  if ENV['BUNDLE_GEMFILE'] =~ /gemfiles/
10
10
  exec 'rake spec'
11
11
  else
12
- Rake::Task['appraise'].execute
12
+ exec 'rake appraise'
13
13
  end
14
14
  end
15
15
 
data/lib/restful_json.rb CHANGED
@@ -1,8 +1,4 @@
1
1
  require 'restful_json/version'
2
2
  require 'restful_json/config'
3
- require 'twinturbo/application_permitter'
4
- require 'twinturbo/controller'
5
- require 'restful_json/base_controller'
6
3
  require 'restful_json/controller'
7
4
  require 'restful_json/default_controller'
8
- require 'restful_json/railtie' if defined? ::Rails::Railtie
@@ -9,6 +9,11 @@ module RestfulJson
9
9
  :return_resource,
10
10
  :render_enabled,
11
11
  :use_permitters,
12
+ :action_to_permitter,
13
+ :allow_action_specific_params_methods,
14
+ :actions_that_authorize,
15
+ :actions_that_permit,
16
+ :actions_supporting_params_methods,
12
17
  :avoid_respond_with,
13
18
  :return_error_data,
14
19
  :rescue_class,
@@ -23,37 +28,76 @@ module RestfulJson
23
28
  end
24
29
 
25
30
  RestfulJson.configure do
31
+
32
+ # default for :using in can_filter_by
26
33
  self.can_filter_by_default_using = [:eq]
34
+
35
+ # to log debug info during request handling
27
36
  self.debug = false
37
+
38
+ # delimiter for values in request parameter values
28
39
  self.filter_split = ','.freeze
40
+
41
+ # equivalent to specifying respond_to :json, :html in the controller, and can be overriden in the controller. Note that by default responders gem sets respond_to :html in application_controller.rb.
29
42
  self.formats = :json, :html
43
+
44
+ # default number of records to return if using the page request function
30
45
  self.number_of_records_in_a_page = 15
46
+
47
+ # delimiter for ARel predicate in the request parameter name
31
48
  self.predicate_prefix = '!'.freeze
49
+
50
+ # if true, will render resource and HTTP 201 for post/create or resource and HTTP 200 for put/update. ignored if render_enabled is false.
32
51
  self.return_resource = false
52
+
53
+ # if false, controller actions will just set instance variable and return it instead of calling setting instance variable and then calling render/respond_with
33
54
  self.render_enabled = true
55
+
56
+ # use Permitters
34
57
  self.use_permitters = true
58
+
59
+ # instead of using Rails default respond_with, explicitly define render in respond_with block
35
60
  self.avoid_respond_with = true
61
+
62
+ # use the permitter_class for create and update, if use_permitters = true
63
+ self.action_to_permitter = {create: nil, update: nil}
64
+
65
+ # the methods that call authorize! action_sym, @model_class
66
+ self.actions_that_authorize = [:create, :update]
67
+
68
+ # if not using permitters, will check respond_to?("(action)_(plural_or_singular_model_name)_params".to_sym) and if true will __send__(method)
69
+ self.allow_action_specific_params_methods = true
70
+
71
+ # if not using permitters, will check respond_to?("(singular_model_name)_params".to_sym) and if true will __send__(method)
72
+ self.actions_that_permit = [:create, :update]
73
+
74
+ # in error JSON, break out the exception info into fields for debugging
36
75
  self.return_error_data = true
37
- # Set to nil to reraise StandardError in rescue vs. calling render_error(e) to render using restful_json
76
+
77
+ # the class that is rescued in each action method, but if nil will always reraise and not handle
38
78
  self.rescue_class = StandardError
79
+
80
+ # will define order of errors handled and what status and/or i18n message key to use
39
81
  self.rescue_handlers = []
40
- # support 404 error for ActiveRecord::RecordNotFound if using ActiveRecord
41
- # errors not loaded yet, so we need to try to require
82
+
83
+ # rescue_handlers are an ordered array of handlers to handle rescue of self.rescue_class or sub types.
84
+ # can use optional i18n_key for message, but will default to e.message if i18n_key not found.
85
+
86
+ # support 404 error for ActiveRecord::RecordNotFound if using ActiveRecord.
42
87
  begin
43
88
  require 'active_record/errors'
44
- RestfulJson.configure do
45
- # Ordered array of handlers to handle rescue of self.rescue_class or sub types. Can use optional i18n_key for message, but will default to e.message if not found.
46
- # Eventually may support [DataMapper::ObjectNotFoundError], [MongoMapper::DocumentNotFound], etc.
47
- # If no exception_classes or exception_ancestor_classes provided, it will always match self.rescue_class.
48
- # Important note: if you specify classes in your configuration, do not specify as strings unless the RestfulJson railtie
49
- # will have a chance to convert it to constants/class objects. See railtie for more info.
50
- self.rescue_handlers = [
51
- {exception_classes: [ActiveRecord::RecordNotFound], status: :not_found, i18n_key: 'api.not_found'.freeze},
52
- ]
53
- end
89
+ self.rescue_handlers << {exception_classes: [ActiveRecord::RecordNotFound], status: :not_found, i18n_key: 'api.not_found'.freeze}
90
+ rescue LoadError, NameError
91
+ end
92
+
93
+ # support 403 error for CanCan::AccessDenied if using CanCan
94
+ begin
95
+ require 'cancan/exceptions'
96
+ self.rescue_handlers << {exception_classes: [CanCan::AccessDenied], status: :forbidden, i18n_key: 'api.not_found'.freeze}
54
97
  rescue LoadError, NameError
55
98
  end
56
99
 
57
- # add default 500 errors last
100
+ # support 500 error for everything else that is a self.rescue_class (in action)
58
101
  self.rescue_handlers << {status: :internal_server_error, i18n_key: 'api.internal_server_error'.freeze}
102
+
59
103
  end
@@ -16,8 +16,8 @@ module RestfulJson
16
16
  module Controller
17
17
  extend ::ActiveSupport::Concern
18
18
 
19
- NILS = ['NULL'.freeze,'null'.freeze,'nil'.freeze]
20
- SINGLE_VALUE_ACTIONS = ['create'.freeze,'update'.freeze,'destroy'.freeze,'new'.freeze]
19
+ NILS = ['NULL'.freeze, 'null'.freeze, 'nil'.freeze]
20
+ SINGLE_VALUE_ACTIONS = [:create, :update, :destroy, :show, :new, :edit]
21
21
 
22
22
  included do
23
23
  # this can be overriden in the controller via defining respond_to
@@ -113,7 +113,7 @@ module RestfulJson
113
113
  # TODO: support custom actions to be automaticaly defined
114
114
  args.each do |an_action|
115
115
  if options[:is]
116
- self.action_to_query[an_action.to_s] = options[:is]
116
+ self.action_to_query[an_action.to_sym] = options[:is]
117
117
  else
118
118
  raise "#{self.class.name} must supply an :is option with query_for #{an_action.inspect}"
119
119
  end
@@ -132,7 +132,7 @@ module RestfulJson
132
132
  self.ordered_by = (Array.wrap(self.ordered_by) + Array.wrap(args)).flatten.compact.collect {|item|item.is_a?(Hash) ? item : {item.to_sym => :asc}}
133
133
  end
134
134
 
135
- # Associate a non-standard ActiveModel Serializer for one or more actions, e.g.
135
+ # Associate a non-standard ActiveModel::Serializer for one or more actions, e.g.
136
136
  # serialize_action :index, with: FoosSerializer
137
137
  # or
138
138
  # serialize_action :index, :some_custom_action, with: FooSerializer
@@ -143,13 +143,27 @@ module RestfulJson
143
143
  options = args.extract_options!
144
144
  args.each do |an_action|
145
145
  if options[:with]
146
- self.action_to_serializer[an_action.to_s] = options[:with]
147
- self.action_to_serializer_for[an_action.to_s] = options[:for] if options[:for]
146
+ self.action_to_serializer[an_action.to_sym] = options[:with]
147
+ self.action_to_serializer_for[an_action.to_sym] = options[:for] if options[:for]
148
148
  else
149
149
  raise "#{self.class.name} must supply an :with option with serialize_action #{an_action.inspect}"
150
150
  end
151
151
  end
152
152
  end
153
+
154
+ # Use default or custom ActionController::Permitter with one or more actions, e.g.
155
+ # permit_action :create, :update # this does nothing because it uses permitter_class, e.g. FooPermitter for FoosController
156
+ # or:
157
+ # permit_action :index, :some_custom_action, with: FoosQueryPermitter
158
+ def permit_action(*args)
159
+ options = args.extract_options!
160
+ args.each do |an_action|
161
+ if options[:with]
162
+ # if key set to nil, it will use the permitter_class method during the action
163
+ self.action_to_permitter[an_action.to_sym] = options[:with]
164
+ end
165
+ end
166
+ end
153
167
  end
154
168
 
155
169
  # In initialize we:
@@ -173,10 +187,12 @@ module RestfulJson
173
187
  @model_at_plural_name_sym = "@#{@model_plural_name}".to_sym
174
188
  @model_at_singular_name_sym = "@#{@model_singular_name}".to_sym
175
189
 
176
- # next 3 are for vanilla strong_parameters
190
+ # default methods for strong parameters
191
+ @model_plural_name_params_sym = "#{@model_plural_name}_params".to_sym
177
192
  @model_singular_name_params_sym = "#{@model_singular_name}_params".to_sym
178
- @create_model_singular_name_params_sym = "create_#{@model_singular_name}_params".to_sym
179
- @update_model_singular_name_params_sym = "update_#{@model_singular_name}_params".to_sym
193
+
194
+ @action_to_singular_action_model_params_method = {}
195
+ @action_to_plural_action_model_params_method = {}
180
196
 
181
197
  underscored_modules_and_underscored_plural_model_name = qualified_controller_name.gsub('::','_').underscore
182
198
 
@@ -228,6 +244,62 @@ module RestfulJson
228
244
  render_error(e, handling_data) unless @performed_render
229
245
  end
230
246
 
247
+ # Finds model using provided info in params, prior to any permittance,
248
+ # via where()...first.
249
+ #
250
+ # Supports composite_keys.
251
+ def find_model_instance
252
+ # to_s as safety measure for vulnerabilities similar to CVE-2013-1854.
253
+ # primary_key array support for composite_primary_keys.
254
+ if @model_class.primary_key.is_a? Array
255
+ c = @model_class
256
+ c.primary_key.each {|pkey|c.where(pkey.to_sym => params[pkey].to_s)}
257
+ @value = c.first
258
+ else
259
+ @value = @model_class.where(@model_class.primary_key.to_sym => params[@model_class.primary_key].to_s).first
260
+ end
261
+ end
262
+
263
+ # Finds model using provided info in params, prior to any permittance,
264
+ # via where()...first! with exception raise if does not exist.
265
+ #
266
+ # Supports composite_keys.
267
+ def find_model_instance!
268
+ # to_s as safety measure for vulnerabilities similar to CVE-2013-1854.
269
+ # primary_key array support for composite_primary_keys.
270
+ if @model_class.primary_key.is_a? Array
271
+ c = @model_class
272
+ c.primary_key.each {|pkey|c.where(pkey.to_sym => params[pkey].to_s)}
273
+ # raise exception if not found
274
+ @value = c.first!
275
+ else
276
+ @value = @model_class.where(@model_class.primary_key.to_sym => params[@model_class.primary_key].to_s).first! # raise exception if not found
277
+ end
278
+ end
279
+
280
+ def allowed_params
281
+ action_sym = params[:action].to_sym
282
+ singular = single_value_response?
283
+ action_specific_params_method = singular ? (@action_to_singular_action_model_params_method[action_sym] ||= "#{action_sym}_#{@model_singular_name}_params".to_sym) : (@action_to_plural_action_model_params_method[action_sym] ||= "#{action_sym}_#{@model_plural_name}_params".to_sym)
284
+ model_name_params_method = singular ? @model_singular_name_params_sym : @model_plural_name_params_sym
285
+
286
+ if self.actions_that_authorize.include?(action_sym)
287
+ authorize! action_sym, @model_class
288
+ end
289
+
290
+ if self.actions_that_permit.include?(action_sym)
291
+ if self.use_permitters
292
+ return permitted_params_using(self.action_to_permitter[action_sym] || permitter_class)
293
+ elsif self.allow_action_specific_params_methods && respond_to?(action_specific_params_method)
294
+ return __send__(action_specific_params_method)
295
+ elsif self.actions_supporting_params_methods.include?(action_sym) && respond_to?(model_name_params_method)
296
+ return __send__(model_name_params_method)
297
+ end
298
+ end
299
+
300
+ params
301
+ end
302
+
231
303
  # Renders error using handling data options (where options are probably hash from self.rescue_handlers that was matched).
232
304
  #
233
305
  # If include_error_data? is true, it returns something like the following (with the appropriate HTTP status code via setting appropriate status in respond_do:
@@ -271,8 +343,8 @@ module RestfulJson
271
343
  respond_with(@value) do |format|
272
344
  format.json do
273
345
  # define local variables in blocks, not outside of them, to be safe, even though would work in this case
274
- custom_action_serializer = self.action_to_serializer[params[:action].to_s]
275
- custom_action_serializer_for = self.action_to_serializer_for[params[:action].to_s]
346
+ custom_action_serializer = self.action_to_serializer[params[:action].to_sym]
347
+ custom_action_serializer_for = self.action_to_serializer_for[params[:action].to_sym]
276
348
  serialization_key = single_value_response? ? (custom_action_serializer_for == :each ? :each_serializer : :serializer) : (custom_action_serializer_for == :array ? :serializer : :each_serializer)
277
349
  if !@value.respond_to?(:errors) || @value.errors.empty?
278
350
  render custom_action_serializer ? {json: @value, status: success_code, serialization_key => custom_action_serializer} : {json: @value, status: success_code}
@@ -283,10 +355,10 @@ module RestfulJson
283
355
  end
284
356
  else
285
357
  # code duplicated from above because local vars don't always traverse well into block (based on wierd ruby-proc bug experienced)
286
- custom_action_serializer = self.action_to_serializer[params[:action].to_s]
287
- custom_action_serializer_for = self.action_to_serializer_for[params[:action].to_s]
358
+ custom_action_serializer = self.action_to_serializer[params[:action].to_sym]
359
+ custom_action_serializer_for = self.action_to_serializer_for[params[:action].to_sym]
288
360
  serialization_key = single_value_response? ? (custom_action_serializer_for == :array ? :serializer : :each_serializer) : (custom_action_serializer_for == :each ? :each_serializer : :serializer)
289
- respond_with @value, custom_action_serializer ? {(self.action_to_serializer_for[params[:action].to_s] == :each ? :each_serializer : :serializer) => custom_action_serializer} : {}
361
+ respond_with @value, custom_action_serializer ? {(self.action_to_serializer_for[params[:action].to_sym] == :each ? :each_serializer : :serializer) => custom_action_serializer} : {}
290
362
  end
291
363
  else
292
364
  @value
@@ -294,7 +366,7 @@ module RestfulJson
294
366
  end
295
367
 
296
368
  def single_value_response?
297
- SINGLE_VALUE_ACTIONS.include?(params[:action].to_s)
369
+ SINGLE_VALUE_ACTIONS.include?(params[:action].to_sym)
298
370
  end
299
371
 
300
372
  # The controller's index (list) method to list resources.
@@ -302,10 +374,11 @@ module RestfulJson
302
374
  # Note: this method be alias_method'd by query_for, so it is more than just index.
303
375
  def index
304
376
  # could be index or another action if alias_method'd by query_for
305
- logger.debug "#{params[:action].to_s} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
377
+ logger.debug "#{params[:action]} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
378
+ p_params = allowed_params
306
379
  t = @model_class.arel_table
307
380
  value = @model_class.scoped # returns ActiveRecord::Relation equivalent to select with no where clause
308
- custom_query = self.action_to_query[params[:action].to_s]
381
+ custom_query = self.action_to_query[params[:action].to_sym]
309
382
  if custom_query
310
383
  value = custom_query.call(t, value)
311
384
  end
@@ -313,12 +386,12 @@ module RestfulJson
313
386
  self.param_to_query.each do |param_name, param_query|
314
387
  if params[param_name]
315
388
  # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
316
- value = param_query.call(t, value, params[param_name].to_s)
389
+ value = param_query.call(t, value, p_params[param_name].to_s)
317
390
  end
318
391
  end
319
392
 
320
393
  self.param_to_through.each do |param_name, through_array|
321
- if params[param_name]
394
+ if p_params[param_name]
322
395
  # build query
323
396
  # e.g. SomeModel.scoped.joins({:assoc_name => {:sub_assoc => {:sub_sub_assoc => :sub_sub_sub_assoc}}).where(sub_sub_sub_assoc_model_table_name: {column_name: value})
324
397
  last_model_class = @model_class
@@ -327,7 +400,7 @@ module RestfulJson
327
400
  if association_or_attribute == through_array.last
328
401
  # must convert param value to string before possibly using with ARel because of CVE-2013-1854, fixed in: 3.2.13 and 3.1.12
329
402
  # https://groups.google.com/forum/?fromgroups=#!msg/rubyonrails-security/jgJ4cjjS8FE/BGbHRxnDRTIJ
330
- value = value.joins(joins).where(last_model_class.table_name.to_sym => {association_or_attribute => params[param_name].to_s})
403
+ value = value.joins(joins).where(last_model_class.table_name.to_sym => {association_or_attribute => p_params[param_name].to_s})
331
404
  else
332
405
  found_classes = last_model_class.reflections.collect {|association_name, reflection| reflection.class_name.constantize if association_name.to_sym == association_or_attribute}.compact
333
406
  if found_classes.size > 0
@@ -350,7 +423,7 @@ module RestfulJson
350
423
  self.param_to_attr_and_arel_predicate.keys.each do |param_name|
351
424
  options = param_to_attr_and_arel_predicate[param_name][2]
352
425
  # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
353
- param = params[param_name].to_s || options[:with_default]
426
+ param = p_params[param_name].to_s || options[:with_default]
354
427
 
355
428
  if param.present? && param_to_attr_and_arel_predicate[param_name]
356
429
  attr_sym = param_to_attr_and_arel_predicate[param_name][0]
@@ -364,42 +437,42 @@ module RestfulJson
364
437
  end
365
438
  end
366
439
 
367
- if params[:page] && self.supported_functions.include?(:page)
368
- page = params[:page].to_i
440
+ if p_params[:page] && self.supported_functions.include?(:page)
441
+ page = p_params[:page].to_i
369
442
  page = 1 if page < 1 # to avoid people using this as a way to get all records unpaged, as that probably isn't the intent?
370
443
  #TODO: to_s is hack to avoid it becoming an Arel::SelectManager for some reason which not sure what to do with
371
444
  value = value.skip((self.number_of_records_in_a_page * (page - 1)).to_s)
372
445
  value = value.take((self.number_of_records_in_a_page).to_s)
373
446
  end
374
447
 
375
- if params[:skip] && self.supported_functions.include?(:skip)
448
+ if p_params[:skip] && self.supported_functions.include?(:skip)
376
449
  # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
377
- value = value.skip(params[:skip].to_s)
450
+ value = value.skip(p_params[:skip].to_s)
378
451
  end
379
452
 
380
- if params[:take] && self.supported_functions.include?(:take)
453
+ if p_params[:take] && self.supported_functions.include?(:take)
381
454
  # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
382
- value = value.take(params[:take].to_s)
455
+ value = value.take(p_params[:take].to_s)
383
456
  end
384
457
 
385
- if params[:uniq] && self.supported_functions.include?(:uniq)
458
+ if p_params[:uniq] && self.supported_functions.include?(:uniq)
386
459
  value = value.uniq
387
460
  end
388
461
 
389
462
  # these must happen at the end and are independent
390
- if params[:count] && self.supported_functions.include?(:count)
463
+ if p_params[:count] && self.supported_functions.include?(:count)
391
464
  value = value.count.to_i
392
- elsif params[:page_count] && self.supported_functions.include?(:page_count)
465
+ elsif p_params[:page_count] && self.supported_functions.include?(:page_count)
393
466
  count_value = value.count.to_i # this executes the query so nothing else can be done in AREL
394
467
  value = (count_value / self.number_of_records_in_a_page) + (count_value % self.number_of_records_in_a_page ? 1 : 0)
395
468
  else
469
+ #TODO: also declaratively specify order via order=attr1,attr2, etc. like can_filter_by w/queries, subattrs, and direction.
396
470
  self.ordered_by.each do |attr_to_direction|
397
471
  # this looks nasty, but makes no sense to iterate keys if only single of each
398
472
  value = value.order(t[attr_to_direction.keys[0]].send(attr_to_direction.values[0]))
399
473
  end
400
474
  value = value.to_a
401
- end
402
-
475
+ end
403
476
  @value = value
404
477
  instance_variable_set(@model_at_plural_name_sym, @value)
405
478
  render_or_respond(true)
@@ -409,9 +482,11 @@ module RestfulJson
409
482
 
410
483
  # The controller's show (get) method to return a resource.
411
484
  def show
412
- logger.debug "#{params[:action].to_s} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
413
- # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
414
- @value = @model_class.where(id: params[:id].to_s).first # don't raise exception if not found
485
+ logger.debug "#{params[:action]} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
486
+ @value = find_model_instance!
487
+ # allowed_params used primarily for authorization. can't do this to get id param(s) because those are sent via route, not
488
+ # in wrapped params (if wrapped)
489
+ allowed_params
415
490
  instance_variable_set(@model_at_singular_name_sym, @value)
416
491
  render_or_respond(true, @value.nil? ? :not_found : :ok)
417
492
  rescue self.rescue_class => e
@@ -420,7 +495,10 @@ module RestfulJson
420
495
 
421
496
  # The controller's new method (e.g. used for new record in html format).
422
497
  def new
423
- logger.debug "#{params[:action].to_s} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
498
+ logger.debug "#{params[:action]} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
499
+ # allowed_params used primarily for authorization. can't do this to get id param(s) because those are sent via route, not
500
+ # in wrapped params (if wrapped)
501
+ allowed_params
424
502
  @value = @model_class.new
425
503
  instance_variable_set(@model_at_singular_name_sym, @value)
426
504
  render_or_respond(true)
@@ -430,9 +508,11 @@ module RestfulJson
430
508
 
431
509
  # The controller's edit method (e.g. used for edit record in html format).
432
510
  def edit
433
- logger.debug "#{params[:action].to_s} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
434
- # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
435
- @value = @model_class.where(id: params[:id].to_s).first! # raise exception if not found
511
+ logger.debug "#{params[:action]} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
512
+ @value = find_model_instance!
513
+ # allowed_params used primarily for authorization. can't do this to get id param(s) because those are sent via route, not
514
+ # in wrapped params (if wrapped)
515
+ allowed_params
436
516
  instance_variable_set(@model_at_singular_name_sym, @value)
437
517
  @value
438
518
  rescue self.rescue_class => e
@@ -441,17 +521,7 @@ module RestfulJson
441
521
 
442
522
  # The controller's create (post) method to create a resource.
443
523
  def create
444
- logger.debug "#{params[:action].to_s} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
445
- if self.use_permitters
446
- authorize! :create, @model_class
447
- allowed_params = permitted_params
448
- elsif respond_to? @create_model_singular_name_params_sym
449
- allowed_params = send(@create_model_singular_name_params_sym)
450
- elsif respond_to? @model_singular_name_params_sym
451
- allowed_params = send(@model_singular_name_params_sym)
452
- else
453
- allowed_params = params
454
- end
524
+ logger.debug "#{params[:action]} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
455
525
  @value = @model_class.new(allowed_params)
456
526
  @value.save
457
527
  instance_variable_set(@model_at_singular_name_sym, @value)
@@ -462,20 +532,12 @@ module RestfulJson
462
532
 
463
533
  # The controller's update (put) method to update a resource.
464
534
  def update
465
- logger.debug "#{params[:action].to_s} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
466
- if self.use_permitters
467
- authorize! :update, @model_class
468
- allowed_params = permitted_params
469
- elsif respond_to? @create_model_singular_name_params_sym
470
- allowed_params = send(@update_model_singular_name_params_sym)
471
- elsif respond_to? @model_singular_name_params_sym
472
- allowed_params = send(@model_singular_name_params_sym)
473
- else
474
- allowed_params = params
475
- end
476
- # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
477
- @value = @model_class.where(id: params[:id].to_s).first # don't raise exception
478
- @value.update_attributes(allowed_params) unless @value.nil?
535
+ logger.debug "#{params[:action]} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
536
+ @value = find_model_instance!
537
+ # allowed_params used primarily for authorization. can't do this to get id param(s) because those are sent via route, not
538
+ # in wrapped params (if wrapped)
539
+ p_params = allowed_params
540
+ @value.update_attributes(p_params) unless @value.nil?
479
541
  instance_variable_set(@model_at_singular_name_sym, @value)
480
542
  render_or_respond(true, @value.nil? ? :not_found : :ok)
481
543
  rescue self.rescue_class => e
@@ -484,9 +546,12 @@ module RestfulJson
484
546
 
485
547
  # The controller's destroy (delete) method to destroy a resource.
486
548
  def destroy
487
- logger.debug "#{params[:action].to_s} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
488
- # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
489
- @value = @model_class.where(id: params[:id].to_s).first # don't raise exception
549
+ logger.debug "#{params[:action]} called in #{self.class}: model=#{@model_class}, request.format=#{request.format}, request.content_type=#{request.content_type}, params=#{params.inspect}" if self.debug
550
+ # don't raise error- DELETE should be idempotent per REST.
551
+ @value = find_model_instance
552
+ # allowed_params used primarily for authorization. can't do this to get id param(s) because those are sent via route, not
553
+ # in wrapped params (if wrapped)
554
+ p_params = allowed_params
490
555
  @value.destroy if @value
491
556
  instance_variable_set(@model_at_singular_name_sym, @value)
492
557
  if !@value.respond_to?(:errors) || @value.errors.empty? || (request.format != 'text/html' && request.content_type != 'text/html')