restful_json 3.1.0 → 3.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.
data/README.md CHANGED
@@ -5,9 +5,15 @@ Develop declarative, featureful JSON RESTful-ish service controllers to use with
5
5
 
6
6
  Should work with Rails 3.1+ and Rails 4. Feel free to submit issues and/or do a pull requests if you run into anything.
7
7
 
8
- For the JSON response, you can either use [active_model_serializers][active_model_serializers], JBuilder, and perhaps others we haven't tested for control over the JSON response format. For active_model_serializers, it also provides the serialize_action class method in the controller to specify custom serializers (assuming you are using a later version of active_model_serializers that works with respond_with). For JBuilder, you can set render_enabled in the config to false.
8
+ Options for JSON response:
9
+ * [active_model_serializers][active_model_serializers] - also provides the serialize_action class method in the controller to specify custom serializers (assuming you are using a later version of active_model_serializers that works with respond_with).
10
+ * JBuilder - to use, set render_enabled in the restful_json config to false.
11
+ * Possibly anything else that works with render/respond_with, or that just adjust the view like JBuilder and don't require extra work in the controller.
9
12
 
10
- For the incoming JSON, it uses Adam Hawkin's [permitter][permitter] code which uses [strong_parameters][strong_parameters] and [cancan][cancan]. Permitters are an object-oriented way of defining what is permitted in the incoming JSON.
13
+ Options for authorizing parameters in incoming JSON (for POSTing create/update):
14
+ * Adam Hawkins' [permitters][permitter] which use [strong_parameters][strong_parameters] and [cancan][cancan]. Permitters are an object-oriented way of defining what is permitted in the incoming JSON, and are a great compliment in the same way that active_model_serializers are. Cancan supports [Authlogic][authlogic], [Devise][devise], etc.
15
+ * [strong_parameters][strong_parameters] - lets you only have to define `(single model name)_params` and/or `create_(single model name)_params` and/or `update_(single model name)_params` which can call require, permit, etc. on params.
16
+ * Mass assignment security in Rails 3.x (attr_accessible, etc.).
11
17
 
12
18
  An example app using restful_json with AngularJS is [employee-training-tracker][employee-training-tracker], featured in [Built with AngularJS][built_with_angularjs].
13
19
 
@@ -38,11 +44,29 @@ If you don't want all of Rails (probably not the case), you at least need action
38
44
  gem 'actionpack', '> 3.1.0'
39
45
  gem 'activerecord', '> 3.1.0'
40
46
 
47
+ #### Strong Parameters
48
+
49
+ Strong Parameters is not required, but is used by default when `self.use_permitters = true`, and if you use `self.use_permitters = false` and specify a `create_(single model name)_params`, `update_(single model name)_params`, and/or `(single model name)_params` methods that use permit, etc. then it would be required.
50
+
51
+ To use [strong_parameters][strong_parameters], in your Gemfile, add:
52
+
53
+ gem 'strong_parameters', '~> 0.1.6'
54
+
55
+ If you're using Rails 3.1.x/3.2.x and you want to disable the default whitelisting that occurs in later versions of Rails because you are going to use Strong Parameters, change the config.active_record.whitelist_attributes property in your `config/application.rb`:
56
+
57
+ config.active_record.whitelist_attributes = false
58
+
59
+ This will allow you to remove / not have to use attr_accessible and do mass assignment inside your code and tests. Instead you will put this information into your permitters.
60
+
61
+ Note that if the Cancan gem is loaded, then, during Rails initialization, it will include `::CanCan::ModelAdditions` in `ActiveRecord::Base`.
62
+
41
63
  #### Cancan
42
64
 
65
+ Cancan is not required if `self.use_permitters = false` in config.
66
+
43
67
  To use [cancan][cancan], in your Gemfile, add:
44
68
 
45
- gem 'cancan', '~> 1.6.7'
69
+ gem 'cancan', '~> 1.6.8'
46
70
 
47
71
  In your `app/controllers/application_controller.rb` or in your service controllers, make sure `current_user` is set:
48
72
 
@@ -54,7 +78,7 @@ In your `app/controllers/application_controller.rb` or in your service controlle
54
78
  end
55
79
  end
56
80
 
57
- You could do that better by setting up some real authentication with [Authlogic][authlogic], [Devise][devise], or whatever cancan will support.
81
+ You could do that better by setting up some real authentication with [Authlogic][authlogic], [Devise][devise], or whatever Cancan will support.
58
82
 
59
83
  In `app/models/ability.rb`, setup a basic cancan ability. Just for testing we'll allow everything:
60
84
 
@@ -66,27 +90,15 @@ In `app/models/ability.rb`, setup a basic cancan ability. Just for testing we'll
66
90
  end
67
91
  end
68
92
 
69
- #### Strong Parameters
70
-
71
- To use [strong_parameters][strong_parameters], in your Gemfile, add:
72
-
73
- gem 'strong_parameters', '~> 0.1.3'
74
-
75
- If you're using Rails 3.1.x/3.2.x and you want to disable the default whitelisting that occurs in later versions of Rails because you are going to use Strong Parameters, change the config.active_record.whitelist_attributes property in your `config/application.rb`:
76
-
77
- config.active_record.whitelist_attributes = false
78
-
79
- This will allow you to remove / not have to use attr_accessible and do mass assignment inside your code and tests. Instead you will put this information into your permitters.
80
-
81
- Note that restful_json automatically includes `ActiveModel::ForbiddenAttributesProtection` on all models, as is done in Rails 4.
93
+ Note that if the Cancan gem is loaded, then, during Rails initialization, it will include `::CanCan::ModelAdditions` in `ActiveRecord::Base`.
82
94
 
83
95
  #### JSON Response Generators
84
96
 
85
97
  ##### ActiveModel Serializers
86
98
 
87
- If you want to use [ActiveModel Serializers][[active_model_serializers], use:
99
+ If you want to use [ActiveModel Serializers][active_model_serializers], use:
88
100
 
89
- gem 'active_model_serializers'
101
+ gem 'active_model_serializers', '~> 0.6.0';
90
102
 
91
103
  Then create your serializers, e.g.:
92
104
 
@@ -127,13 +139,59 @@ Then make sure you add a JBuilder view for each action you require. Although all
127
139
 
128
140
  See [Railscast #320][railscast320] for examples.
129
141
 
142
+ ###### Other
143
+
144
+ Anything that is ok with or without render/responds_with that doesn't require any additional code in the action methods of the controller are ok, e.g. as_json defined in model, etc.
145
+
146
+ #### Create/Update JSON Request/Params Acceptance
147
+
148
+ ##### Permitters
149
+
150
+ We include ApplicationPermitter and optional controller support for Adam Hawkins' [permitters][permitter].
151
+
152
+ Permitters use Cancan for authorization and strong_parameters for parameter whitelisting.
153
+
154
+ We have an implementation of ApplicationPermitter, so you just need permitters in `/app/permitters/`, e.g. `/app/permitters/foobar_permitter.rb`:
155
+
156
+ class FoobarPermitter < ApplicationPermitter
157
+ # attributes we accept (the new way to do attr_accessible, OO-styley! Thanks, twinturbo)
158
+ permit :id, :foo_id
159
+ permit :bar_id
160
+ permit :notes
161
+ # foobar has accepts_nested_attributes_for :barfoos
162
+ scope :barfoos_attributes do |barfoo|
163
+ barfoo.permit :id, :favorite_color, :favorite_chicken
164
+ end
165
+ end
166
+
167
+ If you don't accept anything in create/update, you should have an empty Permitter for the model:
168
+
169
+ class FoobarPermitter < ApplicationPermitter
170
+ end
171
+
172
+ ##### Strong Parameters
173
+
174
+ To use strong_parameters by themselves, without Permitters/Cancan, specify this in restful_json config/controller config:
175
+
176
+ self.use_permitters = false
177
+
178
+ As noted in [strong_parameters], it is suggested to encapsulate the permitting into a private method in the controller, so we've taken that to heart and the controller just attempts to call the relevant *_params method or create_*_params/update_*_params. See below for details.
179
+
180
+ ##### Mass Assignment Security
181
+
182
+ To use mass assignment security in Rails 3.x, specify this in restful_json config/controller config:
183
+
184
+ self.use_permitters = false
185
+
186
+ And make sure that strong_parameters is not loaded.
187
+
130
188
  ### App-level Configuration
131
189
 
132
190
  At the bottom of `config/environment.rb`, you can set config items one at a time like:
133
191
 
134
192
  RestfulJson.debug = true
135
193
 
136
- or in bulk like:
194
+ or in bulk, like:
137
195
 
138
196
  RestfulJson.configure do
139
197
 
@@ -155,8 +213,14 @@ or in bulk like:
155
213
  # delimiter for ARel predicate in the request parameter name
156
214
  self.predicate_prefix = '!'
157
215
 
158
- # if true, will render resource and HTTP 201 for post/create or resource and HTTP 200 for put/update
159
- self.return_resource = false
216
+ # 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.
217
+ self.return_resource = false
218
+
219
+ # if false, controller actions will just set instance variable and return it instead of calling setting instance variable and then calling render/respond_with
220
+ self.render_enabled = true
221
+
222
+ # if false, will assume that it should either try calling create_(single model name)_params or fall back to calling (single model name)_params if create, or update_(single model name)_params then (single model name)_params if that didn't respond, if update.
223
+ self.use_permitters = true
160
224
 
161
225
  end
162
226
 
@@ -172,7 +236,9 @@ All of the app-level configuration parameters are configurable at the controller
172
236
  self.formats = :json, :html
173
237
  self.number_of_records_in_a_page = 15
174
238
  self.predicate_prefix = '!'
175
- self.return_resource = false
239
+ self.return_resource = false
240
+ self.render_enabled = true
241
+ self.use_permitters = true
176
242
 
177
243
  In addition there are some that are controller-only...
178
244
 
@@ -205,11 +271,15 @@ You can have something as simple as:
205
271
 
206
272
  which would use the restful_json configuration and the controller's classname for the service definition.
207
273
 
208
- Or you can define more bells and whistles (read on to see what these do...):
274
+ Or you could have a superclass:
209
275
 
210
- class FoobarsController < ApplicationController
211
-
276
+ class ServiceController < ApplicationController
212
277
  acts_as_restful_json
278
+ end
279
+
280
+ And define more bells and whistles (read on to see what these do...):
281
+
282
+ class FoobarsController < ServiceController
213
283
 
214
284
  query_for :index, is: ->(t,q) {q.joins(:apples, :pears).where(apples: {color: 'green'}).where(pears: {color: 'green'})}
215
285
 
@@ -469,68 +539,7 @@ Note that in `/config/initializers/wrap_parameters.rb` you might need to add `in
469
539
 
470
540
  #### Customing the Default Behavior
471
541
 
472
- In `app/controllers/able_to_mark_on_destroy.rb`, you could have:
473
-
474
- module AbleToMarkOnDestroy
475
- extend ActiveSupport::Concern
476
-
477
- included do
478
- # things you would put in the body of the class
479
- class_attribute :deleted_status_column, instance_writer: true
480
- end
481
-
482
- # no need to define class methods for this example, but this is where you'd do it
483
- #module ClassMethods
484
- #end
485
-
486
- # instance methods from here on out...
487
-
488
- # Note: overriding destroy in restful_json to support marking deleted_status_column with 'deleted'
489
- def destroy
490
- # to_s for vulnerabilities similar to CVE-2013-1854 in older Rails...
491
- @value = @model_class.find(params[:id].to_s)
492
- unless @value.nil? || !self.deleted_status_column
493
- @value.update_attributes!({self.deleted_status_column.to_sym => 'deleted'})
494
- else
495
- @value.destroy
496
- end
497
-
498
- instance_variable_set(@model_at_singular_name_sym, @value)
499
-
500
- if self.render_enabled
501
- # you could take out the custom_action_serializer support if you aren't using
502
- custom_action_serializer = self.action_to_serializer[params[:action].to_s]
503
-
504
- if !@value.nil? && RestfulJson.return_resource
505
- respond_with(@value) do |format|
506
- format.json do
507
- # for errors added in before_destroy validation or in update_attributes
508
- if @value.errors.empty?
509
- render custom_action_serializer ? {json: @value, status: :ok, serializer: custom_action_serializer} : {json: @value, status: :ok}
510
- else
511
- render custom_action_serializer ? {json: {errors: @value.errors}, status: :unprocessable_entity, serializer: custom_action_serializer} : {json: {errors: @value.errors}, status: :unprocessable_entity}
512
- end
513
- end
514
- end
515
- else
516
- respond_with @value, custom_action_serializer ? {serializer: custom_action_serializer} : {}
517
- end
518
- end
519
- end
520
- end
521
-
522
- Then in your controller:
523
-
524
- acts_as_restful_json
525
- include AbleToMarkOnDestroy
526
-
527
- self.deleted_status_column = :foo_deleted
528
-
529
- And when you do a RESTful call to destroy id 123 via a DELETE:
530
-
531
- http://localhost:3000/foobars/123
532
-
533
- Instead of deleting the DB row, the 'foobars' table row's column 'foo_deleted' would be set to 'deleted'.
542
+ Take a look at the controller in `lib/restful_json/controller.rb` to see how the actions are defined, and just copy/paste into your controller or module, etc. and just make sure that it is defined after `acts_as_restful_json` is called.
534
543
 
535
544
  ### Thanks!
536
545
 
@@ -7,7 +7,8 @@ module RestfulJson
7
7
  :number_of_records_in_a_page,
8
8
  :predicate_prefix,
9
9
  :return_resource,
10
- :render_enabled
10
+ :render_enabled,
11
+ :use_permitters
11
12
  ]
12
13
 
13
14
  class << self
@@ -26,4 +27,5 @@ RestfulJson.configure do
26
27
  self.predicate_prefix = '!'
27
28
  self.return_resource = false
28
29
  self.render_enabled = true
30
+ self.use_permitters = true
29
31
  end
@@ -11,10 +11,18 @@ module RestfulJson
11
11
  module ClassMethods
12
12
 
13
13
  def acts_as_restful_json(options = {})
14
- include ::ActionController::Serialization
15
- include ::ActionController::StrongParameters
16
- include ::CanCan::ControllerAdditions
17
- include ::TwinTurbo::Controller
14
+ if defined?(::ActionController::Serialization)
15
+ include ::ActionController::Serialization
16
+ end
17
+ if defined?(::ActionController::StrongParameters)
18
+ include ::ActionController::StrongParameters
19
+ end
20
+ if defined?(::CanCan::ModelAdditions)
21
+ include ::CanCan::ControllerAdditions
22
+ end
23
+ if defined?(::ActionController::StrongParameters) && defined?(::CanCan::ModelAdditions)
24
+ include ::TwinTurbo::Controller
25
+ end
18
26
  include ActsAsRestfulJson
19
27
  end
20
28
 
@@ -173,6 +181,12 @@ module RestfulJson
173
181
  @model_plural_name = self.model_plural_name || @model_singular_name.pluralize
174
182
  @model_at_plural_name_sym = "@#{@model_plural_name}".to_sym
175
183
  @model_at_singular_name_sym = "@#{@model_singular_name}".to_sym
184
+
185
+ # next 3 are for vanilla strong_parameters
186
+ @model_singular_name_params_sym = "#{@model_singular_name}_params".to_sym
187
+ @create_model_singular_name_params_sym = "create_#{@model_singular_name}_params".to_sym
188
+ @update_model_singular_name_params_sym = "update_#{@model_singular_name}_params".to_sym
189
+
176
190
  underscored_modules_and_underscored_plural_model_name = qualified_controller_name.gsub('::','_').underscore
177
191
 
178
192
  # This is a workaround for controllers that are in a different module than the model only works if the controller's base part of the unqualified name in the plural model name.
@@ -289,6 +303,8 @@ module RestfulJson
289
303
  if self.render_enabled
290
304
  custom_action_serializer = self.action_to_serializer[params[:action].to_s]
291
305
  respond_with @value, custom_action_serializer ? {serializer: custom_action_serializer} : {}
306
+ else
307
+ @value
292
308
  end
293
309
  end
294
310
 
@@ -301,6 +317,8 @@ module RestfulJson
301
317
  if self.render_enabled
302
318
  custom_action_serializer = self.action_to_serializer[params[:action].to_s]
303
319
  respond_with @value, custom_action_serializer ? {serializer: custom_action_serializer} : {}
320
+ else
321
+ @value
304
322
  end
305
323
  end
306
324
 
@@ -311,6 +329,8 @@ module RestfulJson
311
329
  if self.render_enabled
312
330
  custom_action_serializer = self.action_to_serializer[params[:action].to_s]
313
331
  respond_with @value, custom_action_serializer ? {serializer: custom_action_serializer} : {}
332
+ else
333
+ @value
314
334
  end
315
335
  end
316
336
 
@@ -319,20 +339,25 @@ module RestfulJson
319
339
  # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
320
340
  @value = @model_class.find(params[:id].to_s)
321
341
  instance_variable_set(@model_at_singular_name_sym, @value)
342
+ @value
322
343
  end
323
344
 
324
345
  # The controller's create (post) method to create a resource.
325
346
  def create
326
- authorize! :create, @model_class
327
- @value = @model_class.new(permitted_params)
347
+ if self.use_permitters
348
+ authorize! :create, @model_class
349
+ allowed_params = permitted_params
350
+ elsif respond_to? @create_model_singular_name_params_sym
351
+ allowed_params = send(@create_model_singular_name_params_sym)
352
+ elsif respond_to? @model_singular_name_params_sym
353
+ allowed_params = send(@model_singular_name_params_sym)
354
+ else
355
+ allowed_params = params
356
+ end
357
+ @value = @model_class.new(allowed_params)
328
358
  @value.save
329
359
  instance_variable_set(@model_at_singular_name_sym, @value)
330
360
 
331
- if self.render_enabled
332
- custom_action_serializer = self.action_to_serializer[params[:action].to_s]
333
- respond_with @value, custom_action_serializer ? {serializer: custom_action_serializer} : {}
334
- end
335
-
336
361
  if self.render_enabled
337
362
  custom_action_serializer = self.action_to_serializer[params[:action].to_s]
338
363
  if !@value.nil? && RestfulJson.return_resource
@@ -348,15 +373,26 @@ module RestfulJson
348
373
  else
349
374
  respond_with @value, custom_action_serializer ? {serializer: custom_action_serializer} : {}
350
375
  end
376
+ else
377
+ @value
351
378
  end
352
379
  end
353
380
 
354
381
  # The controller's update (put) method to update a resource.
355
382
  def update
356
- authorize! :update, @model_class
383
+ if self.use_permitters
384
+ authorize! :update, @model_class
385
+ allowed_params = permitted_params
386
+ elsif respond_to? @create_model_singular_name_params_sym
387
+ allowed_params = send(@update_model_singular_name_params_sym)
388
+ elsif respond_to? @model_singular_name_params_sym
389
+ allowed_params = send(@model_singular_name_params_sym)
390
+ else
391
+ allowed_params = params
392
+ end
357
393
  # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
358
394
  @value = @model_class.find(params[:id].to_s)
359
- @value.update_attributes(permitted_params)
395
+ @value.update_attributes(allowed_params)
360
396
  instance_variable_set(@model_at_singular_name_sym, @value)
361
397
 
362
398
  if self.render_enabled
@@ -374,6 +410,8 @@ module RestfulJson
374
410
  else
375
411
  respond_with @value, custom_action_serializer ? {serializer: custom_action_serializer} : {}
376
412
  end
413
+ else
414
+ @value
377
415
  end
378
416
  end
379
417
 
@@ -386,6 +424,8 @@ module RestfulJson
386
424
 
387
425
  if self.render_enabled
388
426
  respond_with @value, custom_action_serializer ? {serializer: custom_action_serializer} : {}
427
+ else
428
+ @value
389
429
  end
390
430
  end
391
431
 
@@ -4,10 +4,14 @@ module RestfulJson
4
4
  module Model
5
5
  extend ActiveSupport::Concern
6
6
  included do
7
- # strong parameters
8
- include ::ActiveModel::ForbiddenAttributesProtection
9
- # cancan, depended on by twinturbo's permitters
10
- include ::CanCan::ModelAdditions
7
+ if defined?(::ActiveModel::ForbiddenAttributesProtection)
8
+ # strong parameters
9
+ include ::ActiveModel::ForbiddenAttributesProtection
10
+ end
11
+ if defined?(::CanCan::ModelAdditions)
12
+ # cancan, depended on by twinturbo's permitters
13
+ include ::CanCan::ModelAdditions
14
+ end
11
15
  end
12
16
  end
13
17
  end
@@ -1,3 +1,3 @@
1
1
  module RestfulJson
2
- VERSION = '3.1.0'
2
+ VERSION = '3.2.0'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restful_json
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-03-22 00:00:00.000000000 Z
13
+ date: 2013-03-25 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: actionpack
@@ -44,38 +44,6 @@ dependencies:
44
44
  - - ! '>='
45
45
  - !ruby/object:Gem::Version
46
46
  version: 3.1.0
47
- - !ruby/object:Gem::Dependency
48
- name: cancan
49
- requirement: !ruby/object:Gem::Requirement
50
- none: false
51
- requirements:
52
- - - ! '>='
53
- - !ruby/object:Gem::Version
54
- version: 1.6.7
55
- type: :runtime
56
- prerelease: false
57
- version_requirements: !ruby/object:Gem::Requirement
58
- none: false
59
- requirements:
60
- - - ! '>='
61
- - !ruby/object:Gem::Version
62
- version: 1.6.7
63
- - !ruby/object:Gem::Dependency
64
- name: strong_parameters
65
- requirement: !ruby/object:Gem::Requirement
66
- none: false
67
- requirements:
68
- - - ! '>='
69
- - !ruby/object:Gem::Version
70
- version: 0.1.3
71
- type: :runtime
72
- prerelease: false
73
- version_requirements: !ruby/object:Gem::Requirement
74
- none: false
75
- requirements:
76
- - - ! '>='
77
- - !ruby/object:Gem::Version
78
- version: 0.1.3
79
47
  description: Develop declarative, featureful JSON RESTful-ish service controllers
80
48
  to use with modern Javascript MVC frameworks like AngularJS, Ember, etc. with much
81
49
  less code.