restful_json 4.1.0 → 4.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.
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