restful_json 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/README.md +38 -20
- data/lib/restful_json/config.rb +24 -20
- data/lib/restful_json/controller.rb +32 -8
- data/lib/restful_json/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OTZiNzMzYTllNTRkNGQ1N2I1ZjYyOWM4ZDJlZjI3MWQ4ZDMzMTg4Yg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NTRiMGMwZjRmZjllYTJhNTUxZDdhYWQ0ZTIzM2U2OTY0MmJkZTkzZA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
ODZmNGI1MDljOGM4YTRhZmY1OTU5MjAyYzRmZGY5ZGNhZjdmMGJkZTE3OTE0
|
10
|
+
M2M5M2FjMzAxYTMwNDJhMzhlMDY0YWMyNDZmMDk0N2JmNjI5MTg5NDUwMmM5
|
11
|
+
NDU0YWZmOTA0NjMyNTE1MmY3MWU1NGNiNzlkZTk2YjUyNWU1MDk=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZmMwNjgxMDI1ZDhhNjc0YzA3YzUyNDJlZjI0NDZiYTZhYzg0MjJhYTIwNTIx
|
14
|
+
YTEwZWNiYzcwOGVmNTcxYWY1ODc1ODc5NDQ3NzY5YTY0YTAxYmQ5Y2UxZjNk
|
15
|
+
ZjM5OWEwZjIzODk4MDc1MmExM2RjMDQ1NzdiNzZjMzNmNmRlMmY=
|
data/README.md
CHANGED
@@ -252,40 +252,40 @@ or in bulk, like:
|
|
252
252
|
|
253
253
|
```ruby
|
254
254
|
RestfulJson.configure do
|
255
|
-
|
255
|
+
|
256
256
|
# default for :using in can_filter_by
|
257
257
|
self.can_filter_by_default_using = [:eq]
|
258
|
-
|
258
|
+
|
259
259
|
# to log debug info during request handling
|
260
260
|
self.debug = false
|
261
|
-
|
261
|
+
|
262
262
|
# delimiter for values in request parameter values
|
263
263
|
self.filter_split = ','.freeze
|
264
|
-
|
264
|
+
|
265
265
|
# 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.
|
266
266
|
self.formats = :json, :html
|
267
|
-
|
267
|
+
|
268
268
|
# default number of records to return if using the page request function
|
269
269
|
self.number_of_records_in_a_page = 15
|
270
|
-
|
270
|
+
|
271
271
|
# delimiter for ARel predicate in the request parameter name
|
272
272
|
self.predicate_prefix = '!'.freeze
|
273
|
-
|
273
|
+
|
274
274
|
# 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.
|
275
275
|
self.return_resource = false
|
276
|
-
|
276
|
+
|
277
277
|
# if false, controller actions will just set instance variable and return it instead of calling setting instance variable and then calling render/respond_with
|
278
278
|
self.render_enabled = true
|
279
|
-
|
279
|
+
|
280
280
|
# use Permitters
|
281
281
|
self.use_permitters = true
|
282
|
-
|
282
|
+
|
283
283
|
# instead of using Rails default respond_with, explicitly define render in respond_with block
|
284
284
|
self.avoid_respond_with = true
|
285
|
-
|
285
|
+
|
286
286
|
# use the permitter_class for create and update, if use_permitters = true
|
287
287
|
self.action_to_permitter = {create: nil, update: nil}
|
288
|
-
|
288
|
+
|
289
289
|
# the methods that call authorize! action_sym, @model_class
|
290
290
|
self.actions_that_authorize = [:create, :update]
|
291
291
|
|
@@ -294,36 +294,39 @@ RestfulJson.configure do
|
|
294
294
|
|
295
295
|
# if not using permitters, will check respond_to?("(singular_model_name)_params".to_sym) and if true will __send__(method)
|
296
296
|
self.actions_that_permit = [:create, :update]
|
297
|
-
|
297
|
+
|
298
|
+
# will call .includes(...) for including and/or including_for_action when action was generated by query_for
|
299
|
+
self.apply_includes_to_custom_queries = true
|
300
|
+
|
298
301
|
# in error JSON, break out the exception info into fields for debugging
|
299
302
|
self.return_error_data = true
|
300
|
-
|
303
|
+
|
301
304
|
# the class that is rescued in each action method, but if nil will always reraise and not handle
|
302
305
|
self.rescue_class = StandardError
|
303
306
|
|
304
307
|
# will define order of errors handled and what status and/or i18n message key to use
|
305
308
|
self.rescue_handlers = []
|
306
|
-
|
309
|
+
|
307
310
|
# rescue_handlers are an ordered array of handlers to handle rescue of self.rescue_class or sub types.
|
308
311
|
# can use optional i18n_key for message, but will default to e.message if i18n_key not found.
|
309
|
-
|
312
|
+
|
310
313
|
# support 404 error for ActiveRecord::RecordNotFound if using ActiveRecord.
|
311
314
|
begin
|
312
315
|
require 'active_record/errors'
|
313
316
|
self.rescue_handlers << {exception_classes: [ActiveRecord::RecordNotFound], status: :not_found, i18n_key: 'api.not_found'.freeze}
|
314
317
|
rescue LoadError, NameError
|
315
318
|
end
|
316
|
-
|
319
|
+
|
317
320
|
# support 403 error for CanCan::AccessDenied if using CanCan
|
318
321
|
begin
|
319
322
|
require 'cancan/exceptions'
|
320
323
|
self.rescue_handlers << {exception_classes: [CanCan::AccessDenied], status: :forbidden, i18n_key: 'api.not_found'.freeze}
|
321
324
|
rescue LoadError, NameError
|
322
325
|
end
|
323
|
-
|
326
|
+
|
324
327
|
# support 500 error for everything else that is a self.rescue_class (in action)
|
325
328
|
self.rescue_handlers << {status: :internal_server_error, i18n_key: 'api.internal_server_error'.freeze}
|
326
|
-
|
329
|
+
|
327
330
|
end
|
328
331
|
```
|
329
332
|
|
@@ -706,7 +709,7 @@ self.allow_action_specific_params_methods = true
|
|
706
709
|
|
707
710
|
##### Avoid n+1 Queries
|
708
711
|
|
709
|
-
|
712
|
+
Call `include(...) to eager load and avoid n+1 queries:
|
710
713
|
|
711
714
|
```ruby
|
712
715
|
class PostsController < ApplicationController
|
@@ -730,6 +733,21 @@ end
|
|
730
733
|
|
731
734
|
Be careful- Rails doesn't raise an error if it includes associations that don't exist (at least in Rails 3.1-4.0).
|
732
735
|
|
736
|
+
A relevant config option is:
|
737
|
+
|
738
|
+
```ruby
|
739
|
+
self.apply_includes_to_custom_queries = true
|
740
|
+
```
|
741
|
+
|
742
|
+
If that is instead set to true as it is by default, it will also try to call `.includes` on the relation returned from your custom `query_for` query, e.g. if you called index and in the controller defined `including ...` or `including_for_action index: ...`, it will execute your custom query and then take the resuling relation and call `.includes(...)` on it. If `self.apply_includes_to_custom_queries = false`, it won't do that.
|
743
|
+
|
744
|
+
If you have action-specific ActiveModel::Serializers or JBuilder views that require different includes (such as an index action that only includes abbreviated info and a show action that includes more associations), you can handle that with `including_for_action`. Some examples:
|
745
|
+
|
746
|
+
```ruby
|
747
|
+
includes_for :create, are: [:category, :comments]
|
748
|
+
includes_for :index, :a_custom_action, are: [posts: [{comments: :guest}, :tags]]
|
749
|
+
```
|
750
|
+
|
733
751
|
### With Rails-api
|
734
752
|
|
735
753
|
If you want to try out [rails-api][rails-api]:
|
data/lib/restful_json/config.rb
CHANGED
@@ -17,7 +17,8 @@ module RestfulJson
|
|
17
17
|
:avoid_respond_with,
|
18
18
|
:return_error_data,
|
19
19
|
:rescue_class,
|
20
|
-
:rescue_handlers
|
20
|
+
:rescue_handlers,
|
21
|
+
:apply_includes_to_custom_queries
|
21
22
|
]
|
22
23
|
|
23
24
|
class << self
|
@@ -28,40 +29,40 @@ module RestfulJson
|
|
28
29
|
end
|
29
30
|
|
30
31
|
RestfulJson.configure do
|
31
|
-
|
32
|
+
|
32
33
|
# default for :using in can_filter_by
|
33
34
|
self.can_filter_by_default_using = [:eq]
|
34
|
-
|
35
|
+
|
35
36
|
# to log debug info during request handling
|
36
37
|
self.debug = false
|
37
|
-
|
38
|
+
|
38
39
|
# delimiter for values in request parameter values
|
39
40
|
self.filter_split = ','.freeze
|
40
|
-
|
41
|
+
|
41
42
|
# 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.
|
42
43
|
self.formats = :json, :html
|
43
|
-
|
44
|
+
|
44
45
|
# default number of records to return if using the page request function
|
45
46
|
self.number_of_records_in_a_page = 15
|
46
|
-
|
47
|
+
|
47
48
|
# delimiter for ARel predicate in the request parameter name
|
48
49
|
self.predicate_prefix = '!'.freeze
|
49
|
-
|
50
|
+
|
50
51
|
# 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.
|
51
52
|
self.return_resource = false
|
52
|
-
|
53
|
+
|
53
54
|
# if false, controller actions will just set instance variable and return it instead of calling setting instance variable and then calling render/respond_with
|
54
55
|
self.render_enabled = true
|
55
|
-
|
56
|
+
|
56
57
|
# use Permitters
|
57
58
|
self.use_permitters = true
|
58
|
-
|
59
|
+
|
59
60
|
# instead of using Rails default respond_with, explicitly define render in respond_with block
|
60
61
|
self.avoid_respond_with = true
|
61
|
-
|
62
|
+
|
62
63
|
# use the permitter_class for create and update, if use_permitters = true
|
63
64
|
self.action_to_permitter = {create: nil, update: nil}
|
64
|
-
|
65
|
+
|
65
66
|
# the methods that call authorize! action_sym, @model_class
|
66
67
|
self.actions_that_authorize = [:create, :update]
|
67
68
|
|
@@ -70,34 +71,37 @@ RestfulJson.configure do
|
|
70
71
|
|
71
72
|
# if not using permitters, will check respond_to?("(singular_model_name)_params".to_sym) and if true will __send__(method)
|
72
73
|
self.actions_that_permit = [:create, :update]
|
73
|
-
|
74
|
+
|
75
|
+
# will call .includes(...) for including and/or including_for_action when action was generated by query_for
|
76
|
+
self.apply_includes_to_custom_queries = true
|
77
|
+
|
74
78
|
# in error JSON, break out the exception info into fields for debugging
|
75
79
|
self.return_error_data = true
|
76
|
-
|
80
|
+
|
77
81
|
# the class that is rescued in each action method, but if nil will always reraise and not handle
|
78
82
|
self.rescue_class = StandardError
|
79
83
|
|
80
84
|
# will define order of errors handled and what status and/or i18n message key to use
|
81
85
|
self.rescue_handlers = []
|
82
|
-
|
86
|
+
|
83
87
|
# rescue_handlers are an ordered array of handlers to handle rescue of self.rescue_class or sub types.
|
84
88
|
# can use optional i18n_key for message, but will default to e.message if i18n_key not found.
|
85
|
-
|
89
|
+
|
86
90
|
# support 404 error for ActiveRecord::RecordNotFound if using ActiveRecord.
|
87
91
|
begin
|
88
92
|
require 'active_record/errors'
|
89
93
|
self.rescue_handlers << {exception_classes: [ActiveRecord::RecordNotFound], status: :not_found, i18n_key: 'api.not_found'.freeze}
|
90
94
|
rescue LoadError, NameError
|
91
95
|
end
|
92
|
-
|
96
|
+
|
93
97
|
# support 403 error for CanCan::AccessDenied if using CanCan
|
94
98
|
begin
|
95
99
|
require 'cancan/exceptions'
|
96
100
|
self.rescue_handlers << {exception_classes: [CanCan::AccessDenied], status: :forbidden, i18n_key: 'api.not_found'.freeze}
|
97
101
|
rescue LoadError, NameError
|
98
102
|
end
|
99
|
-
|
103
|
+
|
100
104
|
# support 500 error for everything else that is a self.rescue_class (in action)
|
101
105
|
self.rescue_handlers << {status: :internal_server_error, i18n_key: 'api.internal_server_error'.freeze}
|
102
|
-
|
106
|
+
|
103
107
|
end
|
@@ -37,6 +37,7 @@ module RestfulJson
|
|
37
37
|
class_attribute :action_to_serializer, instance_writer: true
|
38
38
|
class_attribute :action_to_serializer_for, instance_writer: true
|
39
39
|
class_attribute :query_includes, instance_writer: true
|
40
|
+
class_attribute :action_to_query_includes, instance_writer: true
|
40
41
|
|
41
42
|
# use values from config
|
42
43
|
RestfulJson::CONTROLLER_OPTIONS.each do |key|
|
@@ -52,6 +53,7 @@ module RestfulJson
|
|
52
53
|
self.param_to_through ||= {}
|
53
54
|
self.action_to_serializer ||= {}
|
54
55
|
self.action_to_serializer_for ||= {}
|
56
|
+
self.action_to_query_includes ||= {}
|
55
57
|
end
|
56
58
|
|
57
59
|
module ClassMethods
|
@@ -105,9 +107,27 @@ module RestfulJson
|
|
105
107
|
self.supported_functions += args
|
106
108
|
end
|
107
109
|
|
110
|
+
# Calls .includes(...) on queries. Take a hash of action as symbol to the includes, e.g. to include(:category, :comments):
|
111
|
+
# including :category, :comments
|
112
|
+
# or includes({posts: [{comments: :guest}, :tags]}):
|
113
|
+
# including posts: [{comments: :guest}, :tags]
|
108
114
|
def including(*args)
|
109
115
|
self.query_includes = args
|
110
116
|
end
|
117
|
+
|
118
|
+
# Calls .includes(...) only on specified action queries. Take a hash of action as symbol to the includes, e.g.:
|
119
|
+
# includes_for :create, are: [:category, :comments]
|
120
|
+
# includes_for :index, :a_custom_action, are: [posts: [{comments: :guest}, :tags]]
|
121
|
+
def includes_for(*args)
|
122
|
+
options = args.extract_options!
|
123
|
+
args.each do |an_action|
|
124
|
+
if options[:are]
|
125
|
+
self.action_to_query_includes.merge!({an_action.to_sym => options[:are]})
|
126
|
+
else
|
127
|
+
raise "#{self.class.name} must supply an :are option with includes_for #{an_action.inspect}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
111
131
|
|
112
132
|
# Specify a custom query. If action specified does not have a method, it will alias_method index to create a new action method with that query.
|
113
133
|
#
|
@@ -274,10 +294,8 @@ module RestfulJson
|
|
274
294
|
# primary_key array support for composite_primary_keys.
|
275
295
|
if @model_class.primary_key.is_a? Array
|
276
296
|
c = @model_class
|
297
|
+
apply_includes params[:action].to_sym, value
|
277
298
|
c.primary_key.each {|pkey|c.where(pkey.to_sym => params[pkey].to_s)}
|
278
|
-
if self.query_includes
|
279
|
-
value.includes(*(self.query_includes))
|
280
|
-
end
|
281
299
|
# raise exception if not found
|
282
300
|
@value = c.first!
|
283
301
|
else
|
@@ -285,6 +303,13 @@ module RestfulJson
|
|
285
303
|
end
|
286
304
|
end
|
287
305
|
|
306
|
+
def apply_includes(action_sym, value)
|
307
|
+
this_includes = self.action_to_query_includes[action_sym] || self.query_includes
|
308
|
+
if this_includes
|
309
|
+
value.includes(*this_includes)
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
288
313
|
def allowed_params
|
289
314
|
action_sym = params[:action].to_sym
|
290
315
|
singular = single_value_response?
|
@@ -383,14 +408,17 @@ module RestfulJson
|
|
383
408
|
def index
|
384
409
|
# could be index or another action if alias_method'd by query_for
|
385
410
|
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
|
411
|
+
action_sym = params[:action].to_sym
|
386
412
|
p_params = allowed_params
|
387
413
|
t = @model_class.arel_table
|
388
414
|
value = @model_class.scoped # returns ActiveRecord::Relation equivalent to select with no where clause
|
389
|
-
custom_query = self.action_to_query[
|
415
|
+
custom_query = self.action_to_query[action_sym]
|
390
416
|
if custom_query
|
391
417
|
value = custom_query.call(t, value)
|
392
418
|
end
|
393
419
|
|
420
|
+
apply_includes action_sym, value
|
421
|
+
|
394
422
|
self.param_to_query.each do |param_name, param_query|
|
395
423
|
if params[param_name]
|
396
424
|
# to_s as safety measure for vulnerabilities similar to CVE-2013-1854
|
@@ -445,10 +473,6 @@ module RestfulJson
|
|
445
473
|
end
|
446
474
|
end
|
447
475
|
|
448
|
-
if self.query_includes
|
449
|
-
value.includes(*(self.query_includes))
|
450
|
-
end
|
451
|
-
|
452
476
|
if p_params[:page] && self.supported_functions.include?(:page)
|
453
477
|
page = p_params[:page].to_i
|
454
478
|
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?
|
data/lib/restful_json/version.rb
CHANGED
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: 4.
|
4
|
+
version: 4.2.0
|
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-05-
|
12
|
+
date: 2013-05-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|