restful_json 3.3.0 → 3.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ODY3NTY5N2RkMDE2ZDI2M2JhMjQ2ZTEwY2RiMjYyMDJiODlmOGU3OA==
4
+ YjYwZWQ2YjYyMTlmYTU5ZDJjNDg3NzBhNWUzMzFiYjA3MTEwYjdkYQ==
5
5
  data.tar.gz: !binary |-
6
- NmJiNTYyMTM0NDRjMWI0NTIzYTIzNmRmY2YyNGYzOGYyZDlhNjUxMw==
6
+ NTQ2MWYxMzMxZDc2Y2E3ZTVjOWU1YzcxNWI1MTk3ZTlkZjI5YjdjNw==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- YzFiZjlhMzA1YWYwM2UxNGExYjZhZDg0MGFmZWM0NjhjNjRhMTBmNmQwYWM5
10
- MTUzMmYwOGJlZDQ0ZDA4MjFiZjRiZjlkMmEzZDY5MjY4MzJmZGFhZGY5NGJh
11
- MTM3Yjc0OTA1YWQ0MGFhYjQwNTgxYzM2M2Y2ZmMzODE5YmQ3ZjM=
9
+ NzRhYjAxZjkwOTRiZDdiNmYyZjRiNGEzZWM2OTQwMTA4NzVhM2UwZjY1ZDg4
10
+ YzYzNjU4MmU4NjJiYjE1ODBhOWRiYzQ3Y2Y4M2Q2M2RjYjhmYzZmOTBmMTU3
11
+ ZDZkYWQyOWIyYmExZmI5NjA0ODQzY2I1NGQxOGFmNTAzZjU5NWU=
12
12
  data.tar.gz: !binary |-
13
- Mjg2ZGU1ZmI5NWY5MjFjOTM4ZmYwZGI0ZjdmMmMxOGIxNmU1NWYxMTA3YTJj
14
- YTk0NjRkMDE2MTVmNjdmMTRiOTBhNzdmZmYzMWZjOTBjYzJjNGNkNTcyYzc5
15
- YTVlYzI5ZTkxMWMzOWMyZDc2ZDFlNDgzZTRlNzAzYWU1NmE2MDI=
13
+ ODhlY2RiMTk3YTFlOGJiMGZiMjBlY2YxMDliMjczMzNiNDJmN2VmYmU2NTY1
14
+ OTUxNzhiNDJhZjMzZjI2ZjdlNWQzMzlhOWE2YThlNjQ3YWJlMmViOGJjOGMw
15
+ YWMwN2NiODVmM2IyNGE3YzMzZDllNTYzNWJjNDU3NTliOTlkNGI=
data/README.md CHANGED
@@ -6,22 +6,22 @@ What does that mean? It means you typically won't have to write index, create, u
6
6
 
7
7
  Why do you need this if Rails controllers already make it easy to provide RESTful JSON services via generated controllers? Because this is just as flexible, almost as declarative, and takes less code. That means your controllers will be easier to read and there will be less code to maintain, but when you need an action method more customized than we can provide, that's all you'll have to write.
8
8
 
9
- restful_json is tested by travis-ci with with Rails 3.1, 3.2, and Rails 4. Feel free to submit issues and/or do a pull requests if you run into anything.
9
+ The goal of the project is to reduce service controller code in an intuitive way, not to be a be-everything DSL or limit what you can do in a controller. Choose what features to expose, and you can still define/redefine actions etc. at will.
10
10
 
11
- Your options for JSON response (the view):
11
+ We test with travis-ci with with Rails 3.1, 3.2, and Rails 4. Feel free to submit issues and/or do a pull requests if you run into anything.
12
+
13
+ You can use any of these for the JSON response (the view):
12
14
  * [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).
13
15
  * JBuilder - to use, set render_enabled in the restful_json config to false.
14
16
  * Just about 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.
15
17
 
16
- Your options for authorizing parameters in incoming JSON (for POSTing create/update):
18
+ And can use any of the following for authorizing parameters in the incoming JSON (for create/update):
17
19
  * 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 ActiveModel::Serializers are. Cancan supports [Authlogic][authlogic], [Devise][devise], etc.
18
20
  * [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.
19
21
  * Mass assignment security in Rails 3.x (attr_accessible, etc.).
20
22
 
21
23
  An example app using an older version of restful_json with AngularJS is [employee-training-tracker][employee-training-tracker], featured in [Built with AngularJS][built_with_angularjs].
22
24
 
23
- The goal of restful_json is to reduce service controller code in an intuitive way, not to be a be-everything DSL. You can choose whether or not to use it and what features to expose at the controller-level, and you can customize controllers and re-define actions/define custom actions.
24
-
25
25
  ### Installation
26
26
 
27
27
  In your Rails app's `Gemfile`:
@@ -41,51 +41,19 @@ Then:
41
41
 
42
42
  bundle install
43
43
 
44
- #### Service Controller Additions
45
-
46
- To clean up your controllers and to make restful_json more flexible and less complex, we suggest use of a module to hold the includes that you'll need depending on what you decide to use. We'll call it ServiceControllerAdditions:
47
-
48
- Create a file called `app/controllers/service_controller_additions.rb` and put this in it:
49
-
50
- module ServiceControllerAdditions
51
- extend ActiveSupport::Concern
52
-
53
- included do
54
- # comment this out if you don't want to use ActiveModel::Seriaizers
55
- include ::ActionController::Serialization
56
- # comment this out if you don't want to use Strong Parameters or Permitters
57
- include ::ActionController::StrongParameters
58
- # comment this out if you don't want to use Permitters
59
- include ::TwinTurbo::Controller
60
- # comment this out if you don't want to use restful_json
61
- include ::RestfulJson::Controller
62
- end
63
-
64
- end
65
-
66
- That way you can just put this at the top of your controller, and will be able to easily extend the functionality of multiple controllers at once, e.g.:
67
-
68
- class FoobarsController < ApplicationController
69
- include ServiceControllerAdditions
70
- end
71
-
72
- However, if you plan to use Permitters and ActiveModel::Serializers, use the "default". It is called the default, because v3 started off with Permitters and ActiveModel::Serializers controller, etc. includes being done by the restful_json gem, which no longer happens:
73
-
74
- class FoobarsController < ApplicationController
75
- include RestfulJson::DefaultController
76
- end
44
+ #### Strong Parameters
77
45
 
78
- `acts_as_restful_json` was deprecated in restful_json 3.3.0. It just calls `include RestfulJson::DefaultController`.
46
+ Strong Parameters is not required, but can be used on its own or as a dependency of Permitters.
79
47
 
80
- #### Strong Parameters
48
+ If you are using Rails 4.x, you might be able to skip this section, as [Strong Parameters][strong_parameters] is included.
81
49
 
82
- If you plan to use Permitters or if you want to use Strong Parameters by itself, you will need to tweak things for [Strong Parameters][strong_parameters] if using Rails 3.x.
50
+ If you are using Rails 3.x, then if you plan to use Permitters or want to use Strong Parameters by itself, you may need to tweak a few things for [Strong Parameters][strong_parameters]
83
51
 
84
52
  To disable the default whitelisting that occurs in later versions of Rails 3.x, set the `config.active_record.whitelist_attributes` property in your `config/application.rb` to false:
85
53
 
86
54
  config.active_record.whitelist_attributes = false
87
55
 
88
- No more attr_accessible needed in your models (so take them out and convert them). Instead you will put this information into your permitters or into `create_(single model name)_params`, `update_(single model name)_params`, and/or `(single model name)_params` methods. Encapsulating what params are permissible in such a method is encouraged and described in the [Strong Parameters][strong_parameters] documentation, used by Rails 4.
56
+ No more attr_accessible needed in your models (so take them out and convert them). Instead you will either put this information into your Permitters, or if you are using Strong Parameters without Permitters, you'll create `create_(single model name)_params`, `update_(single model name)_params`, and/or `(single model name)_params` methods in your controller(s). Encapsulating what params are permissible in such a method is encouraged and described in the [Strong Parameters][strong_parameters] documentation.
89
57
 
90
58
  Strong Parameters (and Permitters) require a model include.
91
59
 
@@ -99,7 +67,11 @@ If you'd rather use Strong Parameters with all models, just put this in your `co
99
67
 
100
68
  #### Cancan
101
69
 
102
- If you are using Permitters, they use [Cancan][cancan], which requires a `current_user` method in your `app/controllers/application_controller.rb` or in your service controllers:
70
+ Though optional, if you decide to use Permitters, the Permitters framework relies on [Cancan][cancan].
71
+
72
+ Permitters are an object-oriented representation of Strong Parameters, but they also integrate with Cancan. Cancan can restrict what resources a given user is allowed to access. In Cancan, all permissions are defined in a single location (the Ability class) and not duplicated across controllers, views, and database queries.
73
+
74
+ To setup Cancan, you need a `current_user` method in your `app/controllers/application_controller.rb` or in your service controllers. For the sake of example, we'll just have it return a new User:
103
75
 
104
76
  class ApplicationController < ActionController::Base
105
77
  protect_from_forgery
@@ -109,9 +81,9 @@ If you are using Permitters, they use [Cancan][cancan], which requires a `curren
109
81
  end
110
82
  end
111
83
 
112
- You could do that better by setting up some real authentication with [Authlogic][authlogic], [Devise][devise], or whatever Cancan will support.
84
+ Cancan integrates [Authlogic][authlogic], [Devise][devise], etc. to return a proper logged-in user or you can return it however you wish.
113
85
 
114
- You also need a `app/models/ability.rb`, setup a basic cancan ability. Just for testing we'll allow everything:
86
+ Cancan also needs an Ability defined in `app/models/ability.rb`. Just for testing we'll ignore the user object and allow everything:
115
87
 
116
88
  class Ability
117
89
  include CanCan::Ability
@@ -129,13 +101,17 @@ Or, if you'd rather use Cancan with all models, just put this in your `config/en
129
101
 
130
102
  ActiveRecord::Base.send(:include, CanCan::ModelAdditions)
131
103
 
132
- If you follow the code above, you'll need a User model, too. Instead of providing a sample one here, we'll leave that open for you to decide on an appropriate implementation after you read through [Authlogic][authlogic], [Devise][devise], etc.
104
+ Once you get everything setup, go through the [Cancan][cancan] documentation, and then [Authlogic][authlogic], [Devise][devise], etc. to setup/integrate with proper authentication and authorization.
133
105
 
134
106
  #### JSON Response Generators
135
107
 
136
108
  ##### ActiveModel Serializers
137
109
 
138
- If you chose to use, [ActiveModel::Serializers][active_model_serializers], you'll eventually want to create one or more serializers for each model that you will be returning via the service(s), e.g.:
110
+ Use of [ActiveModel::Serializers][active_model_serializers] is optional, but a great way to have object-oriented model-like representation of JSON views.
111
+
112
+ The purpose of ActiveModel::Serializers is to provide an object to encapsulate serialization of ActiveModel objects, including ActiveRecord objects. Serializers know about both a model and the current_user, so you can customize serialization based upon whether a user is authorized to see the content. In short, serializers replace hash-driven development with object-oriented development.
113
+
114
+ If you chose to use ActiveModel::Serializers, you'll eventually want to create one or more serializers for each model that you will be returning via the service(s), e.g.:
139
115
 
140
116
  /app/serializers/singular_model_name_serializer.rb
141
117
 
@@ -182,9 +158,9 @@ Then make sure you add a JBuilder view for each action you require. Although all
182
158
 
183
159
  See [Railscast #320][railscast320] for more examples on setting up and using JBuilder.
184
160
 
185
- ###### Other
161
+ ##### Other Options
186
162
 
187
- You should be able to use anything that works with normal render/responds_with in Rails controllers that don't require any additional code in the action methods of the controller are ok, e.g. as_json defined in model, etc.
163
+ You should be able to use anything that works with normal render/responds_with in Rails controllers without additional code in the controller. If you'd like to use something that requires additional code in the action methods of the controller, and you think it would be a good fit, feel free to do a pull request.
188
164
 
189
165
  #### Create/Update JSON Request/Params Acceptance
190
166
 
@@ -246,9 +222,9 @@ Only the main controller is needed:
246
222
 
247
223
  Then, make sure that attr_accessible and/or attr_protected, etc. are used properly.
248
224
 
249
- ### App-level Configuration
225
+ ### Application Configuration
250
226
 
251
- At the bottom of `config/environment.rb`, you can set config items one at a time like:
227
+ At the bottom of `config/environment.rb`, you can set restful_json can be configured one line at a time.
252
228
 
253
229
  RestfulJson.debug = true
254
230
 
@@ -285,7 +261,7 @@ or in bulk, like:
285
261
 
286
262
  end
287
263
 
288
- ### Controller-specific Configuration
264
+ ### Controller Configuration
289
265
 
290
266
  In the controller, you can set a variety of class attributes with `self.something = ...` in the body of your controller.
291
267
 
@@ -318,23 +294,22 @@ Other class attributes are available for setting/overriding, but they are all se
318
294
 
319
295
  ### Usage
320
296
 
321
- You have a configurable generic Rails 3.1+/4+ controller that does the index, show, create, and update and other custom actions easily for you.
297
+ You have a configurable generic Rails 3.1.x/3.2.x/4.0.x controller that does the index, show, create, and update and other custom actions easily for you.
322
298
 
323
299
  Everything is well-declared and fairly concise.
324
300
 
325
301
  You can have something as simple as:
326
302
 
327
303
  class FoobarsController < ApplicationController
328
- include ServiceControllerAdditions
304
+ include RestfulJson::DefaultController
329
305
  end
330
306
 
331
- which would use the restful_json configuration and the controller's classname for the service definition and provide a simple no-frills JSON CRUD controller that behaves mostly like a typical Rails controller created via scaffold.
307
+ which would use the restful_json configuration and the controller's classname for the service definition and provide a simple no-frills JSON CRUD controller that behaves somewhat similarly to a Rails controller created via `rails g scaffold ...`.
332
308
 
333
- Or, you could define more bells and whistles (read on to see what these do...):
309
+ Or, you can define many more bells and whistles:
334
310
 
335
311
  class FoobarsController < ApplicationController
336
-
337
- include ServiceControllerAdditions
312
+ include RestfulJson::DefaultController
338
313
 
339
314
  query_for :index, is: ->(t,q) {q.joins(:apples, :pears).where(apples: {color: 'green'}).where(pears: {color: 'green'})}
340
315
 
@@ -365,6 +340,30 @@ Or, you could define more bells and whistles (read on to see what these do...):
365
340
 
366
341
  end
367
342
 
343
+ #### Routing
344
+
345
+ You can just add normal Rails RESTful routes in `config/routes.rb`, e.g. for the Foobar model:
346
+
347
+ MyAppName::Application.routes.draw do
348
+ resources :foobars
349
+ end
350
+
351
+ Supports static, nested, etc. routes also, e.g.:
352
+
353
+ MyAppName::Application.routes.draw do
354
+ namespace :my_service_controller_module do
355
+ resources :foobars
356
+ end
357
+ end
358
+
359
+ Can pass in params from the path for use in filters, etc. as if they were request parameters:
360
+
361
+ MyAppName::Application.routes.draw do
362
+ namespace :my_service_controller_module do
363
+ match 'bar/:bar_id/foobars(.:format)' => 'foobars#index'
364
+ end
365
+ end
366
+
368
367
  #### Default Filtering by Attribute(s)
369
368
 
370
369
  First, declare in the controller:
@@ -433,7 +432,7 @@ First, declare in the controller:
433
432
 
434
433
  supports_functions :uniq
435
434
 
436
- To return a simple unique view of a model, combine use of an [ActiveModel Serializer][active_model_serializers] that returns just the attribute you want along with the uniq param, e.g. to return unique/distinct colors of foobars you'd have a serializer to just return the color and then use:
435
+ Now this works:
437
436
 
438
437
  http://localhost:3000/foobars?uniq=
439
438
 
@@ -443,27 +442,25 @@ First, declare in the controller:
443
442
 
444
443
  supports_functions :count
445
444
 
446
- This is another filter that can be used with the others, but instead of returning the json objects, it returns their count, which is useful for paging to determine how many results you can page through:
445
+ Now this works:
447
446
 
448
447
  http://localhost:3000/foobars?count=
449
448
 
450
449
  ##### Paging
451
450
 
452
- In controller make sure these are included:
451
+ First, declare in the controller:
453
452
 
454
453
  supports_functions :page, :page_count
455
454
 
456
- To get the first page of results:
455
+ Now you can get the page count:
457
456
 
458
- http://localhost:3000/foobars?page=1
457
+ http://localhost:3000/foobars?page_count=
459
458
 
460
- To get the second page of results:
459
+ And access each page of results:
461
460
 
461
+ http://localhost:3000/foobars?page=1
462
462
  http://localhost:3000/foobars?page=2
463
-
464
- To get the total number of pages of results:
465
-
466
- http://localhost:3000/foobars?page_count=
463
+ ...
467
464
 
468
465
  To set page size at application level:
469
466
 
@@ -473,11 +470,9 @@ To set page size at controller level:
473
470
 
474
471
  self.number_of_records_in_a_page = 15
475
472
 
476
- For a better idea of how this works on the backend, look at [ARel][arel]'s skip and take, or see Variable Paging.
473
+ ##### Skip and Take (OFFSET and LIMIT)
477
474
 
478
- ###### Skip and Take (OFFSET and LIMIT)
479
-
480
- In controller make sure these are included:
475
+ First, declare in the controller:
481
476
 
482
477
  supports_functions :skip, :take
483
478
 
@@ -489,47 +484,25 @@ To limit the number of rows returned, use 'take'. It is called take, because tak
489
484
 
490
485
  http://localhost:3000/foobars.json?take=5
491
486
 
492
- Combine skip and take for manual completely customized paging.
493
-
494
- Get the first page of 15 results:
487
+ Combine skip and take for manual completely customized paging, e.g.
495
488
 
496
489
  http://localhost:3000/foobars?take=15
497
-
498
- Second page of 15 results:
499
-
500
490
  http://localhost:3000/foobars?skip=15&take=15
501
-
502
- Third page of 15 results:
503
-
504
491
  http://localhost:3000/foobars?skip=30&take=15
505
492
 
506
- First page of 30 results:
507
-
508
- http://localhost:3000/foobars?take=30
509
-
510
- Second page of 30 results:
511
-
512
- http://localhost:3000/foobars?skip=30&take=30
513
-
514
- Third page of 30 results:
515
-
516
- http://localhost:3000/foobars?skip=60&take=30
517
-
518
493
  ##### Custom Serializers
519
494
 
520
- If using ActiveModel::Serializers, you can use something other than the (singular model name)Serializer via serialize_action:
495
+ If using ActiveModel::Serializers, you can use something other than the `(singular model name)Serializer` via `serialize_action`:
521
496
 
522
497
  serialize_action :index, with: ListFoobarSerializer
523
498
 
524
499
  The built-in actions that support custom serializers (you can add more) are: index, show, new, create, update, destroy, and any action you automatically have created via using the restful_json `query_for` method.
525
500
 
526
- It will use `serialize` for single result actions like show, new, create, update, destroy, and `serialize_each` with index and custom actions.
527
-
528
- To override, specify `for:` with `:array` or `:each`, e.g.:
501
+ It will use the `serializer` option for single result actions like show, new, create, update, destroy, and the `each_serializer` option with index and custom actions. Or, you can specify `for:` with `:array` or `:each`, e.g.:
529
502
 
530
503
  serialize_action :index, :some_custom_action, with: FoosSerializer, for: :array
531
504
 
532
- And, you can just use the default serialization provided by AMS if you want. No class needed.
505
+ Or, you could just use the default serialization, if you want.
533
506
 
534
507
  ##### Custom Queries
535
508
 
@@ -538,7 +511,12 @@ To filter the list where the status_code attribute is 'green':
538
511
  # t is self.model_class.arel_table and q is self.model_class.scoped
539
512
  query_for :index, is: lambda {|t,q| q.where(:status_code => 'green')}
540
513
 
541
- or use the `->` Ruby 1.9 lambda stab operator. You can also filter out items that have associations that don't have a certain attribute value (or anything else you can think up with [ARel][arel]/[ActiveRecord relations][ar]). To filter the list where the object's apples and pears associations are green:
514
+ or use the `->` Ruby 1.9 lambda stab operator (note lack of whitespace between stab and parenthesis):
515
+
516
+ # t is self.model_class.arel_table and q is self.model_class.scoped
517
+ query_for :index, is: is: ->(t,q) {q.where(:status_code => 'green')}
518
+
519
+ You can also filter out items that have associations that don't have a certain attribute value (or anything else you can think up with [ARel][arel]/[ActiveRecord relations][ar]), e.g. to filter the list where the object's apples and pears associations are green:
542
520
 
543
521
  # t is self.model_class.arel_table and q is self.model_class.scoped
544
522
  # note: must be no space between -> and parenthesis
@@ -550,7 +528,9 @@ or use the `->` Ruby 1.9 lambda stab operator. You can also filter out items tha
550
528
 
551
529
  ##### Define Custom Actions with Custom Queries
552
530
 
553
- `query_for` also will `alias_method (some action), :index` anything other than `:index`, so you can easily create custom non-RESTful action methods:
531
+ You are still working with regular controllers here, so add or override methods if you want more!
532
+
533
+ However `query_for` will create new action methods, so you can easily create custom non-RESTful action methods:
554
534
 
555
535
  # t is self.model_class.arel_table and q is self.model_class.scoped
556
536
  # note: must be no space between -> and parenthesis in lambda syntax!
@@ -558,31 +538,35 @@ or use the `->` Ruby 1.9 lambda stab operator. You can also filter out items tha
558
538
 
559
539
  Note that it is a proc so you can really do whatever you want with it and will have access to other things in the environment or can call another method, etc.
560
540
 
561
- You are still working with regular controllers here, so add or override methods if you want more!
562
-
563
- ### Routing
541
+ query_for :some_action, is: ->(t,q) do
542
+ if @current_user.admin?
543
+ Rails.logger.debug("Notice: unfiltered results provided to admin #{@current_user.name}")
544
+ # just make sure the relation is returned!
545
+ q
546
+ else
547
+ q.where(:access => 'public')
548
+ end
549
+ end
564
550
 
565
- Respects regular and nested Rails resourceful routing and controller namespacing, e.g. in `config/routes.rb`:
551
+ Be sure to add a route for that action, e.g. in `config/routes.rb`, e.g. for the Barfoo model:
566
552
 
567
- MyAwesomeApp::Application.routes.draw do
568
- namespace :my_service_controller_module do
569
- resources :foobars
570
- # why use nested if you only want to provide ways of querying via path
571
- match 'bars/:bar_id/foobars(.:format)' => 'foobars#index'
553
+ MyAppName::Application.routes.draw do
554
+ resources :barfoos do
555
+ get 'some_action', :on => :collection
572
556
  end
573
557
  end
574
558
 
575
559
  ### With Rails-api
576
560
 
577
- If you want to try out [rails-api][rails-api], maybe use:
561
+ If you want to try out [rails-api][rails-api]:
578
562
 
579
563
  gem 'rails-api', '~> 0.0.3'
580
564
 
581
- In `apps/controllers/restful_json_api.rb`:
565
+ In `app/controllers/my_service_controller.rb`:
582
566
 
583
- module RestfulJsonApi
567
+ module MyServiceController
584
568
  extend ActiveSupport::Concern
585
-
569
+
586
570
  included do
587
571
  # Rails-api lets you choose features. You might not need all of these, or may need others.
588
572
  include AbstractController::Translation
@@ -591,25 +575,25 @@ In `apps/controllers/restful_json_api.rb`:
591
575
  include ActionController::MimeResponds
592
576
  include ActionController::Cookies
593
577
  include ActionController::ParamsWrapper
578
+
579
+ # use Permitters and AMS
594
580
  include RestfulJson::DefaultController
581
+ # or comment that last line and uncomment whatever you want to use
582
+ #include ::ActionController::Serialization # AMS
583
+ #include ::ActionController::StrongParameters
584
+ #include ::TwinTurbo::Controller # Permitters which uses Cancan and Strong Parameters
585
+ #include ::RestfulJson::Controller
595
586
 
596
587
  # If you want any additional inline class stuff, it goes here...
597
- end
598
-
599
- module ClassMethods
600
- # Any additional class methods...
601
- end
602
-
603
- # Instance methods...
604
-
588
+ end
605
589
  end
606
590
 
607
591
  class FoobarsController < ActionController::API
608
- include RestfulJsonApi
592
+ include MyServiceController
609
593
  end
610
594
 
611
595
  class BarfoosController < ActionController::API
612
- include RestfulJsonApi
596
+ include MyServiceController
613
597
  end
614
598
 
615
599
  Note that in `/config/initializers/wrap_parameters.rb` you might need to add `include ActionController::ParamsWrapper` prior to the `wrap_parameters` call. For example, for unwrapped JSON, it would look like:
@@ -630,6 +614,8 @@ Note that in `/config/initializers/wrap_parameters.rb` you might need to add `in
630
614
 
631
615
  ##### Parent/Ancestor Class Definition Not Supported
632
616
 
617
+ Don't subclass and include in the parent, that puts the class attributes into the parent which means they would be shared by the children and bad things can happen.
618
+
633
619
  Don't do this:
634
620
 
635
621
  class ServiceController < ApplicationController
@@ -639,72 +625,81 @@ Don't do this:
639
625
  include ::RestfulJson::Controller
640
626
  end
641
627
 
642
- # nor should you do this
643
- #class FoobarsController < ApplicationController
644
- # include RestfulJson::DefaultController
645
- #end
646
-
647
628
  class FoobarsController < ServiceController
648
629
  end
649
630
 
650
631
  class BarfoosController < ServiceController
651
632
  end
652
633
 
653
- It may appear to work when using the same controller or even on each new controller load, but when you make requests to BarfoosController, make a request to FoobarsController, and then make a request back to the BarfoosController, it may fail in very strange ways, such as missing column(s) from SQL results (because it isn't using the correct model).
654
-
655
- Do as a module instead!
656
-
657
- ##### Customizing Behavior via Module
658
-
659
- Remember how we created a `apps/controllers/service_controller_additions.rb`?
660
-
661
- You can add behavior to it!
634
+ And don't do this:
662
635
 
663
- Let's add a method so that `hello :world` in the controller will make it return `{"hello": "world"}`:
636
+ class FoobarsController < ApplicationController
637
+ include RestfulJson::DefaultController
638
+ end
639
+
640
+ class FoobarsController < ServiceController
641
+ end
642
+
643
+ class BarfoosController < ServiceController
644
+ end
664
645
 
665
- module HelloWorld
666
- extend ActiveSupport::Concern
667
- included do
668
- # see notes in Service Controller Additions section of restful_json doc for what is needed
669
- include ::ActionController::Serialization
670
- include ::ActionController::StrongParameters
671
- include ::TwinTurbo::Controller
672
- include ::RestfulJson::Controller
673
-
674
- # let's add a name that can be set with a class method
675
- class_attribute :name, instance_writer: true
676
- end
646
+ It may appear to work when using the same controller or even on each new controller load, but when you make requests to BarfoosController, make a request to FoobarsController, and then make a request back to the BarfoosController, it may fail in very strange ways, such as missing column(s) from SQL results (because it isn't using the correct model).
677
647
 
678
- module ClassMethods
679
- def hello(value)
680
- self.name = value.to_sym
648
+ ##### Customizing Behavior via Patch
649
+
650
+ In `config/initializers/restful_json.rb` you can monkey patch the RestfulJson::Controller module. The DefaultController includes that, so it will get your changes also:
651
+
652
+ # a horrible Hello World example
653
+ module RestfulJson
654
+ module Controller
655
+
656
+ # class methods that should be implemented or overriden
657
+ module ClassMethods
658
+ def hello(name)
659
+ #TODO: find way to call hook into the block call in RJ controller's included block
660
+ # without having do funny things to ActiveSupport::Concern, because append_features(base)
661
+ # defined in the monkey patch is never called, and module_eval is a royal pain.
662
+ # Or, stop using ActiveSupport::Concern. For now, we'll defined class_attribute in the
663
+ # class method that uses it and use respond_to? in a nasty hack. I'm sorry.
664
+ class_attribute :name, instance_writer: true
665
+ self.name = name
666
+ end
681
667
  end
682
- end
683
668
 
684
- def index
685
- respond_to do |format|
686
- format.json do
687
- render :json => {"hello" => self.name}.to_json
688
- end
669
+ # instance methods that should be implemented or overriden.
670
+ #
671
+ # note: you don't have to do this to override service methods at the controller-level.
672
+ # Instead, just define them in the controller. this is just an example of monkey-patching.
673
+ def index
674
+ name = self.respond_to?(:name) && self.name ? self.name : 'nobody'
675
+ render :json => {:hello => self.name}
676
+ rescue => e
677
+ # rescue to identify errors that otherwise can be swallowed
678
+ puts "index failed: #{self} #{e}"
679
+ raise e
689
680
  end
681
+
690
682
  end
691
683
  end
692
684
 
693
- Then:
685
+ Now in your controller, if you:
694
686
 
695
687
  class FoobarsController < ApplicationController
696
- include HelloWorld
697
- hello :world
688
+ include RestfulJson::DefaultController
689
+ hello 'world'
698
690
  end
699
691
 
700
- class BarfoosController < ApplicationController
701
- include HelloWorld
702
- hello :world
703
- end
692
+ (Note again: RestfulJson::DefaultController includes RestfulJson::Controller.)
704
693
 
705
- For more realistic use that takes advantage of existing configuration in the controller, 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.
694
+ Now when you call:
695
+
696
+ http://localhost:3000/foobars
706
697
 
707
- Make sure that the inclusion of your module is defined after `include RestfulJson::Controller`, `include RestfulJson::DefaultController`, or `acts_as_restful_json` is called.
698
+ You would get the response:
699
+
700
+ {'hello': 'world'}
701
+
702
+ For more realistic use that takes advantage of existing configuration in the controller, 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.
708
703
 
709
704
  ### Release Notes
710
705
 
@@ -734,9 +729,9 @@ Include this in `config/environment.rb`
734
729
 
735
730
  ### Rails Version-specific Eccentricities
736
731
 
737
- Strong Parameters is included in Rails 4. Rails 4.1 and up will need `gem 'activerecord-deprecated_finders' gem, at least for now. (At time of writing Rails 4.1 is not out yet, so not a problem.)
732
+ Strong Parameters is included in Rails 4.
738
733
 
739
- If you are using Rails 3.1, note that respond_with returns HTTP 200 instead of 204 for update and destroy, unless return_resource is true.
734
+ If you are using Rails 3.1.x, note that respond_with returns HTTP 200 instead of 204 for update and destroy, unless return_resource is true.
740
735
 
741
736
  ### Thanks!
742
737
 
@@ -200,14 +200,19 @@ module RestfulJson
200
200
 
201
201
  def render_or_respond(read_only_action, success_code = :ok)
202
202
  if self.render_enabled
203
- if !@value.nil? && ((read_only_action && RestfulJson.return_resource) || RestfulJson.avoid_respond_with)
203
+ # 404/not found is just for update (not destroy, because idempotent destroy = no 404)
204
+ if success_code == :not_found
205
+ respond_to do |format|
206
+ format.html { render :file => "#{Rails.root}/public/404.html", :status => :not_found }
207
+ format.any { head :not_found }
208
+ end
209
+ elsif !@value.nil? && ((read_only_action && RestfulJson.return_resource) || RestfulJson.avoid_respond_with)
204
210
  respond_with(@value) do |format|
205
211
  format.json do
206
212
  # define local variables in blocks, not outside of them, to be safe, even though would work in this case
207
213
  custom_action_serializer = self.action_to_serializer[params[:action].to_s]
208
214
  custom_action_serializer_for = self.action_to_serializer_for[params[:action].to_s]
209
215
  serialization_key = single_value_response? ? (custom_action_serializer_for == :each ? :each_serializer : :serializer) : (custom_action_serializer_for == :array ? :serializer : :each_serializer)
210
- puts "serialization key = #{serialization_key}, custom_action_serializer = #{custom_action_serializer}"
211
216
  if !@value.respond_to?(:errors) || @value.errors.empty?
212
217
  render custom_action_serializer ? {json: @value, status: success_code, serialization_key => custom_action_serializer} : {json: @value, status: success_code}
213
218
  else
@@ -390,17 +395,22 @@ module RestfulJson
390
395
  allowed_params = params
391
396
  end
392
397
  # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
393
- @value = @model_class.find(params[:id].to_s)
394
- @value.update_attributes(allowed_params)
398
+ @value = @model_class.where(id: params[:id].to_s).to_a[0]
399
+ status = :ok
400
+ if @value.nil?
401
+ status = :not_found
402
+ else
403
+ @value.update_attributes(allowed_params)
404
+ end
395
405
  instance_variable_set(@model_at_singular_name_sym, @value)
396
- render_or_respond(false)
406
+ render_or_respond(false, status)
397
407
  end
398
408
 
399
409
  # The controller's destroy (delete) method to destroy a resource.
400
410
  def destroy
401
411
  # to_s as safety measure for vulnerabilities similar to CVE-2013-1854
402
- @value = @model_class.find(params[:id].to_s)
403
- @value.destroy
412
+ @value = @model_class.where(id: params[:id].to_s).to_a[0]
413
+ @value.destroy if @value
404
414
  instance_variable_set(@model_at_singular_name_sym, @value)
405
415
  render_or_respond(false)
406
416
  end
@@ -1,3 +1,3 @@
1
1
  module RestfulJson
2
- VERSION = '3.3.0'
2
+ VERSION = '3.3.1'
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.3.0
4
+ version: 3.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gary S. Weaver
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-05 00:00:00.000000000 Z
12
+ date: 2013-04-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - ! '>='
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: simplecov
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
42
56
  description: Develop declarative, featureful JSON RESTful-ish service controllers
43
57
  to use with modern Javascript MVC frameworks like AngularJS, Ember, etc. with much
44
58
  less code.