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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- YjBiNTMxMDFhMDg0NDIwMTMzNzg1ZDVhYmQxYTlkNzM0OThiZTg2ZQ==
4
+ OTZiNzMzYTllNTRkNGQ1N2I1ZjYyOWM4ZDJlZjI3MWQ4ZDMzMTg4Yg==
5
5
  data.tar.gz: !binary |-
6
- NjhjODQ3Yzc2Nzk4MTI0ZTkxYjI3MmMwYTBlNTZlY2U1ZTkwOTM1Ng==
6
+ NTRiMGMwZjRmZjllYTJhNTUxZDdhYWQ0ZTIzM2U2OTY0MmJkZTkzZA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- YzhkZGIwMzA4YzAzNjYyYWRjMmMzOTgwYTJiZDk1OGEwNjQ5MGQ1N2EzNGMx
10
- NGM3MmQ4NDU2N2U4YmQzYWVlYmQzMTBiMTcxOTI4ZGY5Y2JkMDdjMzUyNTgx
11
- NzYxYzk1YWZiY2I1NzUxYTQ5NTA0MzJmMGU2YWRlODQzOGI1MzM=
9
+ ODZmNGI1MDljOGM4YTRhZmY1OTU5MjAyYzRmZGY5ZGNhZjdmMGJkZTE3OTE0
10
+ M2M5M2FjMzAxYTMwNDJhMzhlMDY0YWMyNDZmMDk0N2JmNjI5MTg5NDUwMmM5
11
+ NDU0YWZmOTA0NjMyNTE1MmY3MWU1NGNiNzlkZTk2YjUyNWU1MDk=
12
12
  data.tar.gz: !binary |-
13
- MGY3NTJiOWNiOGE5MDZjMTBjMTllYTNiYmIzZjg1MDgyZDQ1OTc3MzZiZGMx
14
- ZWZhMjliZTAwNTExNmFlZTcwZjM2MDZiZTQ0MTUyMDQ5YjRiMjcyYWIzMDMx
15
- ZTI3MGU5OTM5NDQ0YjZkMWY0ZTAzZDQ0ZGEwMmMyZWIzZjcyODE=
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
- Unless using a custom query, if you specify `including {some hash}`, that will add `.includes({some hash})` to any automatically generated queries (in the proper place) such that eager loading can be used to avoid n+1 queries:
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]:
@@ -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[params[:action].to_sym]
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?
@@ -1,3 +1,3 @@
1
1
  module RestfulJson
2
- VERSION = '4.1.0'
2
+ VERSION = '4.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: 4.1.0
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-01 00:00:00.000000000 Z
12
+ date: 2013-05-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport