restful_json 3.4.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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')