graphiti 2.0.0.beta.8 → 2.0.0.beta.10

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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +1 -1
  3. data/.github/workflows/docs.yml +9 -6
  4. data/.github/workflows/release.yml +1 -1
  5. data/CHANGELOG.md +43 -0
  6. data/Rakefile +28 -0
  7. data/UPGRADING.md +1 -1
  8. data/lib/generators/graphiti/generator_mixin.rb +24 -0
  9. data/lib/generators/graphiti/templates/application_resource.rb.erb +9 -16
  10. data/lib/graphiti/configuration.rb +66 -28
  11. data/lib/graphiti/debugger.rb +18 -6
  12. data/lib/graphiti/delegates/pagination.rb +2 -2
  13. data/lib/graphiti/error_serializers/deprecated_constants.rb +23 -0
  14. data/lib/graphiti/error_serializers/invalid_request.rb +6 -0
  15. data/lib/graphiti/errors.rb +51 -3
  16. data/lib/graphiti/query.rb +36 -14
  17. data/lib/graphiti/rails/controller.rb +26 -6
  18. data/lib/graphiti/rails/rake_helpers.rb +17 -0
  19. data/lib/graphiti/rails.rb +14 -0
  20. data/lib/graphiti/railtie.rb +8 -0
  21. data/lib/graphiti/request_validators/update_validator.rb +1 -1
  22. data/lib/graphiti/request_validators/validator.rb +9 -0
  23. data/lib/graphiti/resource/configuration.rb +138 -40
  24. data/lib/graphiti/resource/dsl.rb +21 -2
  25. data/lib/graphiti/resource/interface.rb +1 -1
  26. data/lib/graphiti/resource/links.rb +36 -5
  27. data/lib/graphiti/resource/remote.rb +2 -1
  28. data/lib/graphiti/resource/sideloading.rb +2 -2
  29. data/lib/graphiti/schema.rb +2 -2
  30. data/lib/graphiti/scope.rb +115 -23
  31. data/lib/graphiti/scoping/filter.rb +4 -4
  32. data/lib/graphiti/scoping/paginate.rb +3 -3
  33. data/lib/graphiti/serializer.rb +12 -6
  34. data/lib/graphiti/sideload/polymorphic_belongs_to.rb +11 -4
  35. data/lib/graphiti/sideload.rb +22 -14
  36. data/lib/graphiti/spec_helpers/matchers.rb +2 -2
  37. data/lib/graphiti/spec_helpers/rspec.rb +6 -3
  38. data/lib/graphiti/util/link.rb +1 -1
  39. data/lib/graphiti/util/serializer_attributes.rb +5 -3
  40. data/lib/graphiti/util/serializer_relationships.rb +26 -16
  41. data/lib/graphiti/version.rb +1 -1
  42. data/lib/graphiti.rb +6 -1
  43. data/lib/tasks/graphiti.rake +4 -0
  44. data/package-lock.json +114 -0
  45. data/package.json +16 -3
  46. metadata +3 -2
@@ -30,14 +30,34 @@ module Graphiti
30
30
 
31
31
  register_exception Graphiti::Errors::InvalidRequest,
32
32
  status: 400, handler: Graphiti::Rails::InvalidRequestHandler
33
- register_exception Graphiti::Errors::ConflictRequest,
34
- status: 409, handler: Graphiti::Rails::ConflictRequestHandler
35
- register_exception Graphiti::Errors::RecordNotFound,
36
- status: 404, handler: Graphiti::Rails::ExceptionHandler
37
33
  register_exception Graphiti::Errors::RemoteWrite,
38
- status: 400, handler: Graphiti::Rails::ExceptionHandler
34
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
39
35
  register_exception Graphiti::Errors::SingularSideload,
40
- status: 400, handler: Graphiti::Rails::ExceptionHandler
36
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
37
+ register_exception Graphiti::Errors::InvalidInclude,
38
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
39
+ register_exception Graphiti::Errors::UnsupportedSort,
40
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
41
+ register_exception Graphiti::Errors::UnsupportedOperator,
42
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
43
+ register_exception Graphiti::Errors::InvalidFilterValue,
44
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
45
+ register_exception Graphiti::Errors::RequiredFilter,
46
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
47
+ register_exception Graphiti::Errors::UnsupportedPageSize,
48
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
49
+ register_exception Graphiti::Errors::UnsupportedBeforeCursor,
50
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
51
+ register_exception Graphiti::Errors::UnsupportedPagination,
52
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
53
+ register_exception Graphiti::Errors::FilterGroupMissingRequiredFilters,
54
+ status: 400, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
55
+
56
+ register_exception Graphiti::Errors::RecordNotFound,
57
+ status: 404, detail: :exception, handler: Graphiti::Rails::ExceptionHandler
58
+
59
+ register_exception Graphiti::Errors::ConflictRequest,
60
+ status: 409, handler: Graphiti::Rails::ConflictRequestHandler
41
61
  end
42
62
  end
43
63
  end
@@ -21,6 +21,23 @@ module Graphiti
21
21
  ::Rails.application.config.action_controller.perform_caching = false
22
22
  end
23
23
 
24
+ # The pool and RAILS_MAX_THREADS are read from this environment, and production may size both differently.
25
+ def connection_pool_advisory
26
+ return unless defined?(ActiveRecord::Base)
27
+
28
+ pool = ActiveRecord::Base.connection_db_config.pool
29
+ threads = ENV.fetch("RAILS_MAX_THREADS", 5).to_i
30
+ sideload_threads = Graphiti.config.concurrency_max_threads
31
+ needed = threads + sideload_threads + 1
32
+ return if pool.nil? || pool >= needed
33
+
34
+ "WARNING database.yml pool is #{pool} in this environment. With concurrency on (the production default), " \
35
+ "each sideload holds its own connection, so pool should be at least " \
36
+ "web threads (#{threads}) + concurrency_max_threads (#{sideload_threads}) + 1 = #{needed}. " \
37
+ "If production sizes these differently, check the numbers there. " \
38
+ "See graphiti.dev/concepts/resources#concurrency-pool-sizing."
39
+ end
40
+
24
41
  def make_request(path, debug = false)
25
42
  if path.split("/").length == 2
26
43
  path = "#{ApplicationResource.endpoint_namespace}#{path}"
@@ -31,6 +31,13 @@ module Graphiti
31
31
  autoload :Responders, "graphiti/rails/responders"
32
32
  autoload :TestHelpers, "graphiti/rails/test_helpers"
33
33
 
34
+ # Deprecated. Backed graphiti-rails' enable!/disable! spec toggles. Remove in 3.0.
35
+ GraphitiErrorsTesting = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
36
+ "Graphiti::Rails::GraphitiErrorsTesting",
37
+ "Graphiti::Rails::TestHelpers",
38
+ DEPRECATOR
39
+ )
40
+
34
41
  # @!attribute self.handled_exception_formats
35
42
  # A list of formats as symbols whose exceptions will be handled by Graphiti. See {Railtie}.
36
43
  cattr_accessor :handled_exception_formats, default: []
@@ -47,6 +54,13 @@ module Graphiti
47
54
  "Graphiti::Rails::Responders",
48
55
  DEPRECATOR
49
56
  )
57
+
58
+ # Deprecated. Core's railtie merged into graphiti-rails'. Remove in 3.0.
59
+ Railtie = ActiveSupport::Deprecation::DeprecatedConstantProxy.new(
60
+ "Graphiti::Railtie",
61
+ "Graphiti::Rails::Railtie",
62
+ DEPRECATOR
63
+ )
50
64
  end
51
65
 
52
66
  ActiveSupport.on_load(:active_record) do
@@ -0,0 +1,8 @@
1
+ # Deprecated require path, kept so a leftover 1.x require does not raise.
2
+ # The railtie lives in Graphiti::Rails as of 2.0. Remove in 3.0.
3
+ require "graphiti"
4
+
5
+ Graphiti::DEPRECATOR.warn(
6
+ 'require "graphiti/railtie" is no longer needed. The railtie is part of the Rails ' \
7
+ "integration as of 2.0, and loads with graphiti when Rails is present."
8
+ )
@@ -2,7 +2,7 @@ module Graphiti
2
2
  module RequestValidators
3
3
  class UpdateValidator < Validator
4
4
  def validate
5
- if required_payload? && payload_matches_endpoint?
5
+ if validate_data_shape && required_payload? && payload_matches_endpoint?
6
6
  super
7
7
  else
8
8
  false
@@ -17,6 +17,7 @@ module Graphiti
17
17
  # In the future these should have their own validation logic, but
18
18
  # for now we can just bypass
19
19
  return errors.blank? unless @params.has_key?(:data)
20
+ return false unless validate_data_shape
20
21
 
21
22
  resource = @root_resource
22
23
  if @params[:data].has_key?(:type)
@@ -56,6 +57,14 @@ module Graphiti
56
57
  @errors.add(:page, :invalid, message: "must be an object")
57
58
  end
58
59
 
60
+ def validate_data_shape
61
+ data = @params[:data]
62
+ return true if data.nil? || data.respond_to?(:each_pair)
63
+
64
+ @errors.add(:data, :invalid, message: "must be an object")
65
+ false
66
+ end
67
+
59
68
  def process_relationships(resource, relationships, payload_path)
60
69
  relationships.each_key do |name|
61
70
  unless resource.class.sideload(name.to_sym)
@@ -4,16 +4,75 @@ module Graphiti
4
4
  extend ActiveSupport::Concern
5
5
 
6
6
  DEFAULT_MAX_PAGE_SIZE = 1_000
7
+ LINK_MODES = [true, false, :on_demand].freeze
8
+ BELONGS_TO_RESOURCE_IDS_MODES = [:foreign_key, :always, :never].freeze
9
+ BLANK_MODES = [:as_literal, :as_nil, :reject].freeze
10
+
11
+ # Grouped for the ApplicationResource the install generator writes.
12
+ SETTING_GROUPS = { # :nodoc:
13
+ attributes: {
14
+ attributes_readable_by_default: {default: true},
15
+ attributes_writable_by_default: {default: true},
16
+ attributes_sortable_by_default: {default: true},
17
+ attributes_filterable_by_default: {default: true},
18
+ attributes_schema_by_default: {default: true},
19
+ typecast_reads: {default: true}
20
+ },
21
+ relationships: {
22
+ relationships_readable_by_default: {default: true},
23
+ relationships_writable_by_default: {default: true},
24
+ belongs_to_resource_ids_by_default: {
25
+ default: :foreign_key,
26
+ values: BELONGS_TO_RESOURCE_IDS_MODES,
27
+ invalid: ->(klass, value) { Errors::InvalidBelongsToResourceIds.new(klass, value) }
28
+ }
29
+ },
30
+ filters: {
31
+ filters_blanks_by_default: {
32
+ default: :as_literal,
33
+ values: BLANK_MODES,
34
+ invalid: ->(klass, value) { Errors::InvalidFilterBlanks.new(klass, :filters_blanks_by_default, value) }
35
+ }
36
+ },
37
+ sorting: {
38
+ default_sort: {default: nil, note: "per resource, e.g. [{id: :desc}]"}
39
+ },
40
+ pagination: {
41
+ page_default_size: {default: nil, note: "unset falls back to 20"},
42
+ page_max_size: {default: DEFAULT_MAX_PAGE_SIZE, format: "1_000"},
43
+ page_cursors: {default: false, note: "render cursors for pagination"},
44
+ page_links: {
45
+ default: false,
46
+ values: LINK_MODES,
47
+ invalid: ->(klass, value) { Errors::InvalidLinkRendering.new(klass, :page_links, value) }
48
+ }
49
+ },
50
+ endpoints: {
51
+ validate_requests: {default: true, note: "refuse requests to undeclared endpoints"}
52
+ },
53
+ links: {
54
+ relationship_links: {
55
+ default: true,
56
+ values: LINK_MODES,
57
+ invalid: ->(klass, value) { Errors::InvalidLinkRendering.new(klass, :relationship_links, value) }
58
+ },
59
+ validate_links: {default: true, note: "refuse to render links to unroutable endpoints"}
60
+ }
61
+ }.freeze
62
+
63
+ SETTINGS = SETTING_GROUPS.values.reduce(:merge).freeze # :nodoc:
7
64
 
8
65
  module Overrides
9
- BELONGS_TO_RESOURCE_IDS_VALUES = [:foreign_key, :always, :never].freeze
66
+ SETTINGS.each_pair do |name, setting|
67
+ next unless setting[:values]
10
68
 
11
- def belongs_to_resource_ids_by_default=(val)
12
- unless BELONGS_TO_RESOURCE_IDS_VALUES.include?(val)
13
- raise Errors::InvalidBelongsToResourceIds.new(self, val)
14
- end
69
+ define_method(:"#{name}=") do |val|
70
+ unless setting[:values].include?(val)
71
+ raise setting[:invalid].call(self, val)
72
+ end
15
73
 
16
- super
74
+ super(val)
75
+ end
17
76
  end
18
77
 
19
78
  def serializer=(val)
@@ -95,51 +154,37 @@ module Graphiti
95
154
  :polymorphic,
96
155
  :polymorphic_child,
97
156
  :serializer,
98
- :default_page_size,
99
- :default_sort,
100
- :max_page_size,
101
- :attributes_readable_by_default,
102
- :attributes_writable_by_default,
103
- :attributes_sortable_by_default,
104
- :attributes_filterable_by_default,
105
- :attributes_schema_by_default,
106
- :relationships_readable_by_default,
107
- :relationships_writable_by_default,
108
- :belongs_to_resource_ids_by_default,
109
- :filters_accept_nil_by_default,
110
- :filters_deny_empty_by_default,
111
157
  :graphql_entrypoint,
112
- :cursor_paginatable
158
+ *SETTINGS.keys
113
159
 
114
160
  class << self
115
161
  prepend Overrides
116
162
  end
117
163
 
164
+ SETTINGS.each_pair do |name, setting|
165
+ public_send(:"#{name}=", setting[:default])
166
+ end
167
+
118
168
  def self.inherited(klass)
119
169
  super
120
170
  klass.config = Util::Hash.deep_dup(config)
121
171
  klass.adapter ||= Adapters::Abstract
122
- klass.max_page_size ||= DEFAULT_MAX_PAGE_SIZE
123
172
  # re-assigning causes a new Class.new
124
173
  klass.serializer = (klass.serializer || klass.infer_serializer_superclass)
125
174
  klass.type ||= klass.infer_type
126
175
  klass.graphql_entrypoint = klass.type.to_s.pluralize.to_sym
127
- default(klass, :attributes_readable_by_default, true)
128
- default(klass, :attributes_writable_by_default, true)
129
- default(klass, :attributes_sortable_by_default, true)
130
- default(klass, :attributes_filterable_by_default, true)
131
- default(klass, :attributes_schema_by_default, true)
132
- default(klass, :relationships_readable_by_default, true)
133
- default(klass, :relationships_writable_by_default, true)
134
- default(klass, :belongs_to_resource_ids_by_default, :foreign_key)
135
- default(klass, :filters_accept_nil_by_default, false)
136
- default(klass, :filters_deny_empty_by_default, false)
137
-
138
176
  unless klass.config[:attributes][:id]
139
177
  klass.attribute :id, :integer_id
140
178
  end
141
179
  klass.stat total: [:count]
142
180
 
181
+ # An abstract parent has no serializer for its sideloads, so the subclass applies them here.
182
+ if abstract_class?
183
+ klass.config[:sideloads].each_pair do |name, sideload|
184
+ klass.apply_sideload_to_serializer(name) if klass.eagerly_apply_sideload?(sideload)
185
+ end
186
+ end
187
+
143
188
  if defined?(::Rails) && ::Rails.env.development?
144
189
  # Avoid adding dupe resources when re-autoloading
145
190
  Graphiti.resources.reject! { |r| r.name == klass.name }
@@ -149,6 +194,52 @@ module Graphiti
149
194
  end
150
195
 
151
196
  class_methods do
197
+ # Deprecated. Both folded into filters_blanks_by_default. Remove in 3.0.
198
+ def filters_accept_nil_by_default
199
+ filters_blanks_by_default == :as_nil
200
+ end
201
+
202
+ def filters_accept_nil_by_default=(val)
203
+ self.filters_blanks_by_default = val ? :as_nil : :as_literal
204
+ end
205
+
206
+ def filters_deny_empty_by_default
207
+ filters_blanks_by_default == :reject
208
+ end
209
+
210
+ def filters_deny_empty_by_default=(val)
211
+ self.filters_blanks_by_default = val ? :reject : :as_literal
212
+ end
213
+
214
+ # Deprecated. Renamed to the page_ family. Remove in 3.0.
215
+ def default_page_size
216
+ page_default_size
217
+ end
218
+
219
+ def default_page_size=(val)
220
+ self.page_default_size = val
221
+ end
222
+
223
+ def max_page_size
224
+ page_max_size
225
+ end
226
+
227
+ def max_page_size=(val)
228
+ self.page_max_size = val
229
+ end
230
+
231
+ def cursor_paginatable
232
+ page_cursors
233
+ end
234
+
235
+ def cursor_paginatable=(val)
236
+ self.page_cursors = val
237
+ end
238
+
239
+ def cursor_paginatable?
240
+ !!page_cursors
241
+ end
242
+
152
243
  def get_attr!(name, flag, opts = {})
153
244
  opts[:raise_error] = true
154
245
  get_attr(name, flag, opts)
@@ -205,14 +296,6 @@ module Graphiti
205
296
  serializer_class
206
297
  end
207
298
 
208
- def default(object, attr, value)
209
- prior = object.send(attr)
210
- unless prior || prior == false
211
- object.send(:"#{attr}=", value)
212
- end
213
- end
214
- private :default
215
-
216
299
  def config
217
300
  @config ||=
218
301
  {
@@ -332,5 +415,20 @@ module Graphiti
332
415
  self.class.default_filters
333
416
  end
334
417
  end
418
+
419
+ blanks_msg = "Use `self.filters_blanks_by_default` (:as_literal, :as_nil, or :reject)"
420
+ page_msg = "Use `self.page_default_size`, `self.page_max_size` and `self.page_cursors`"
421
+ DEPRECATOR.deprecate_methods(Configuration::ClassMethods,
422
+ filters_accept_nil_by_default: blanks_msg,
423
+ "filters_accept_nil_by_default=": blanks_msg,
424
+ filters_deny_empty_by_default: blanks_msg,
425
+ "filters_deny_empty_by_default=": blanks_msg,
426
+ default_page_size: page_msg,
427
+ "default_page_size=": page_msg,
428
+ max_page_size: page_msg,
429
+ "max_page_size=": page_msg,
430
+ cursor_paginatable: page_msg,
431
+ "cursor_paginatable=": page_msg,
432
+ cursor_paginatable?: page_msg)
335
433
  end
336
434
  end
@@ -40,8 +40,7 @@ module Graphiti
40
40
  required: required,
41
41
  schema: schema,
42
42
  operators: operators.to_hash,
43
- allow_nil: opts.fetch(:allow_nil, filters_accept_nil_by_default),
44
- deny_empty: opts.fetch(:deny_empty, filters_deny_empty_by_default)
43
+ blanks: blanks_for(name, opts)
45
44
  }
46
45
  elsif (type = args[0])
47
46
  attribute name, type, only: [:filterable], allow: opts[:allow]
@@ -206,6 +205,26 @@ module Graphiti
206
205
  end
207
206
  end
208
207
  private :relationship_option
208
+
209
+ def blanks_for(name, opts)
210
+ if opts.key?(:deny_empty)
211
+ DEPRECATOR.warn("The deny_empty: filter option is deprecated. Use blanks: :reject.")
212
+ return :reject if opts[:deny_empty]
213
+ end
214
+
215
+ if opts.key?(:allow_nil)
216
+ DEPRECATOR.warn("The allow_nil: filter option is deprecated. Use blanks: :as_nil.")
217
+ return opts[:allow_nil] ? :as_nil : :as_literal
218
+ end
219
+
220
+ blanks = opts.fetch(:blanks, filters_blanks_by_default)
221
+ unless Resource::BLANK_MODES.include?(blanks)
222
+ raise Errors::InvalidFilterBlanks.new(self, name, blanks)
223
+ end
224
+
225
+ blanks
226
+ end
227
+ private :blanks_for
209
228
  end
210
229
  end
211
230
  end
@@ -80,7 +80,7 @@ module Graphiti
80
80
  end
81
81
 
82
82
  def validate_request!(params)
83
- return if Graphiti.context[:graphql] || !validate_endpoints?
83
+ return if Graphiti.context[:graphql] || !validate_requests?
84
84
 
85
85
  if context&.respond_to?(:request)
86
86
  path = context.request.env["PATH_INFO"]
@@ -25,12 +25,8 @@ module Graphiti
25
25
  class_attribute :endpoint,
26
26
  :base_url,
27
27
  :endpoint_namespace,
28
- :secondary_endpoints,
29
- :autolink,
30
- :validate_endpoints
28
+ :secondary_endpoints
31
29
  self.secondary_endpoints = []
32
- self.autolink = true
33
- self.validate_endpoints = true
34
30
 
35
31
  class << self
36
32
  prepend Overrides
@@ -38,6 +34,33 @@ module Graphiti
38
34
  end
39
35
 
40
36
  class_methods do
37
+ # Deprecated. Folded into relationship_links. Remove in 3.0.
38
+ def autolink
39
+ relationship_links != false
40
+ end
41
+
42
+ def autolink=(val)
43
+ self.relationship_links = val ? true : false
44
+ end
45
+
46
+ def autolink?
47
+ autolink
48
+ end
49
+
50
+ # Deprecated. Split into validate_requests and validate_links. Remove in 3.0.
51
+ def validate_endpoints
52
+ validate_requests && validate_links
53
+ end
54
+
55
+ def validate_endpoints=(val)
56
+ self.validate_requests = val
57
+ self.validate_links = val
58
+ end
59
+
60
+ def validate_endpoints?
61
+ validate_endpoints
62
+ end
63
+
41
64
  def infer_endpoint
42
65
  return unless name
43
66
 
@@ -101,4 +124,12 @@ module Graphiti
101
124
  end
102
125
  end
103
126
  end
127
+
128
+ msg = "Use `self.relationship_links` (true, false, or :on_demand)"
129
+ endpoints_msg = "Use `self.validate_requests` for inbound requests, `self.validate_links` for rendered links"
130
+ DEPRECATOR.deprecate_methods(Links::ClassMethods,
131
+ autolink: msg, "autolink=": msg, autolink?: msg,
132
+ validate_endpoints: endpoints_msg,
133
+ "validate_endpoints=": endpoints_msg,
134
+ validate_endpoints?: endpoints_msg)
104
135
  end
@@ -6,7 +6,8 @@ module Graphiti
6
6
  included do
7
7
  self.adapter = Graphiti::Adapters::GraphitiAPI
8
8
  self.model = OpenStruct
9
- self.validate_endpoints = false
9
+ self.validate_requests = false
10
+ self.validate_links = false
10
11
 
11
12
  class_attribute :timeout,
12
13
  :open_timeout
@@ -126,11 +126,11 @@ module Graphiti
126
126
  end
127
127
 
128
128
  # If eager loading, ensure routes are loaded first, then apply
129
- # This happens in Railtie
129
+ # This happens in Railtie. Setup runs once, so classes redefined by a reload apply at definition.
130
130
  def eagerly_apply_sideload?(sideload)
131
131
  # TODO: Maybe handle this in the Rails integration
132
132
  if defined?(::Rails) && (app = ::Rails.application)
133
- app.config.eager_load ? false : true
133
+ app.config.eager_load ? Graphiti.setup? : true
134
134
  else
135
135
  sideload.resource_class_loaded?
136
136
  end
@@ -111,8 +111,8 @@ module Graphiti
111
111
  config[:default_sort] = default_sort
112
112
  end
113
113
 
114
- if r.default_page_size
115
- config[:default_page_size] = r.default_page_size
114
+ if r.page_default_size
115
+ config[:default_page_size] = r.page_default_size
116
116
  end
117
117
 
118
118
  if r.polymorphic? && !r.polymorphic_child?