Skip to content

Commit 611ee2e

Browse files
Merge pull request #33 from SwitchDreams/feature/pagination
[SW-2104] Feature/pagination
2 parents 96dce40 + 1a4e954 commit 611ee2e

File tree

13 files changed

+338
-3
lines changed

13 files changed

+338
-3
lines changed

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ Metrics/AbcSize:
2727
RSpec/ExampleLength:
2828
Max: 6
2929

30+
RSpec/AnyInstance:
31+
Enabled: false
32+
3033
Metrics/BlockLength:
3134
AllowedMethods: [ 'describe', 'context' ]
3235

Gemfile.lock

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
PATH
22
remote: .
33
specs:
4-
rest-api-generator (0.1.6)
4+
rest-api-generator (0.1.7)
55
anyway_config (>= 2.0.0)
6+
pagy
67
rails (>= 5.0)
78

89
GEM
@@ -129,6 +130,7 @@ GEM
129130
racc (~> 1.4)
130131
nokogiri (1.13.10-x86_64-linux)
131132
racc (~> 1.4)
133+
pagy (6.0.3)
132134
parallel (1.22.1)
133135
parser (3.1.3.0)
134136
ast (~> 2.4.1)

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Following [Switch Dreams's](https://www.switchdreams.com.br/]) coding practices,
2424
- :memo: [Automated documentation](#specsdocs)
2525
- [Resource ordering](#ordering)
2626
- [Resource filter](#filtering)
27+
- [Resource pagination](#pagination)
2728
- [Configurable](#configuration)
2829

2930
## Next Features
@@ -294,6 +295,34 @@ And It's done, you can filter your index end-point:
294295

295296
- `GET /cars?color=blue or GET /cars?color=red&name=Ferrari`
296297

298+
### Pagination
299+
300+
For pagination, you need to create pagy initialializer file (pagy.rb) in the config directory of your project. Follow [pagy's example](https://ddnexus.github.io/pagy/quick-start/) for more information.
301+
302+
Next, you should add some lines on top of the previously created pagy file:
303+
304+
```ruby
305+
# config/initializers/pagy.rb
306+
require "pagy"
307+
require "pagy/extras/headers"
308+
```
309+
310+
At last, change the pagination variable on RestApiGenerator initializer to true;
311+
312+
```rb
313+
# config/initializers/rest_api_generator.rb
314+
config.pagination = true # default: false
315+
```
316+
317+
Note, if the parent controller is changed, it is necessary to include Pagy::Backend in the new parent.
318+
319+
```rb
320+
# new_parent_controller.rb
321+
class NewParentController < ActionController::Base
322+
include Pagy::Backend
323+
end
324+
```
325+
297326
## Configuration
298327

299328
You can override this gem configuration using the initializer or any other method from [anyway_config](https://github.com/palkan/anyway_config):
@@ -305,6 +334,7 @@ RestApiGenerator.configure do |config|
305334
config.test_path = "custom_test_dir/requests" # default: spec/requests
306335
config.docs_path = "custom_docs_dir/rswag" # default: spec/docs
307336
config.parent_class = "ApplicationController" # default: RestApiGenerator::ResourceController
337+
config.pagination = true # default: false
308338
end
309339
```
310340

app/controllers/rest_api_generator/application_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44

55
module RestApiGenerator
66
class ApplicationController < ActionController::Base
7+
include Pagy::Backend
78
end
89
end

app/controllers/rest_api_generator/child_resource_controller.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ def index
1111
@resources = resources
1212
@resources = @resources.filter_resource(params_for_filter) if resource_class.include?(Filterable)
1313
@resources = @resources.order(ordering_params(params[:sort])) if params[:sort]
14+
if pagination
15+
@pagy, @resources = pagy(@resources)
16+
pagy_headers_merge(@pagy)
17+
end
1418
render json: @resources, status: :ok
1519
end
1620

@@ -93,5 +97,9 @@ def parent_record_id
9397
def record_id
9498
params.permit(:id)[:id]
9599
end
100+
101+
def pagination
102+
RestApiGenerator.configuration.pagination
103+
end
96104
end
97105
end

app/controllers/rest_api_generator/resource_controller.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ def index
1010
@resources = resource_class.all
1111
@resources = @resources.filter_resource(params_for_filter) if resource_class.include?(Filterable)
1212
@resources = @resources.order(ordering_params(params[:sort])) if params[:sort]
13+
if pagination
14+
@pagy, @resources = pagy(@resources)
15+
pagy_headers_merge(@pagy)
16+
end
1317
render json: @resources, status: :ok
1418
end
1519

@@ -69,5 +73,9 @@ def resource_by_controller_name(controller_name = self.class.to_s)
6973
def record_id
7074
params.permit(:id)[:id]
7175
end
76+
77+
def pagination
78+
RestApiGenerator.configuration.pagination
79+
end
7280
end
7381
end

lib/rest_api_generator/config.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class Config < Anyway::Config
1010

1111
attr_config test_path: "spec/requests",
1212
docs_path: "spec/docs",
13-
parent_controller: "RestApiGenerator::ApplicationController"
13+
parent_controller: "RestApiGenerator::ApplicationController",
14+
pagination: false
1415
end
1516
end

lib/rest_api_generator/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module RestApiGenerator
4-
VERSION = "0.1.6"
4+
VERSION = "0.1.7"
55
end

rest-api-generator.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Gem::Specification.new do |spec|
3838
spec.metadata["rubygems_mfa_required"] = "true"
3939

4040
spec.add_dependency "anyway_config", ">= 2.0.0"
41+
spec.add_dependency "pagy"
4142
spec.add_dependency "rails", ">= 5.0"
4243

4344
spec.add_development_dependency "ammeter", "~> 1.1.5"
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# frozen_string_literal: true
2+
3+
require "pagy"
4+
5+
# Pagy initializer file (6.0.1)
6+
# Customize only what you really need and notice that the core Pagy works also without any of the following lines.
7+
# Should you just cherry pick part of this file, please maintain the require-order of the extras
8+
9+
# Pagy DEFAULT Variables
10+
# See https://ddnexus.github.io/pagy/docs/api/pagy#variables
11+
# All the Pagy::DEFAULT are set for all the Pagy instances but can be overridden per instance by just passing them to
12+
# Pagy.new|Pagy::Countless.new|Pagy::Calendar::*.new or any of the #pagy* controller methods
13+
14+
# Instance variables
15+
# See https://ddnexus.github.io/pagy/docs/api/pagy#instance-variables
16+
# Pagy::DEFAULT[:page] = 1 # default
17+
# Pagy::DEFAULT[:items] = 20 # default
18+
# Pagy::DEFAULT[:outset] = 0 # default
19+
20+
# Other Variables
21+
# See https://ddnexus.github.io/pagy/docs/api/pagy#other-variables
22+
# Pagy::DEFAULT[:size] = [1,4,4,1] # default
23+
# Pagy::DEFAULT[:page_param] = :page # default
24+
# The :params can be also set as a lambda e.g ->(params){ params.exclude('useless').merge!('custom' => 'useful') }
25+
# Pagy::DEFAULT[:params] = {} # default
26+
# Pagy::DEFAULT[:fragment] = '#fragment' # example
27+
# Pagy::DEFAULT[:link_extra] = 'data-remote="true"' # example
28+
# Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default
29+
# Pagy::DEFAULT[:cycle] = true # example
30+
# Pagy::DEFAULT[:request_path] = "/foo" # example
31+
32+
# Extras
33+
# See https://ddnexus.github.io/pagy/categories/extra
34+
35+
# Backend Extras
36+
37+
# Arel extra: For better performance utilizing grouped ActiveRecord collections:
38+
# See: https://ddnexus.github.io/pagy/docs/extras/arel
39+
# require 'pagy/extras/arel'
40+
41+
# Array extra: Paginate arrays efficiently, avoiding expensive array-wrapping and without overriding
42+
# See https://ddnexus.github.io/pagy/docs/extras/array
43+
# require 'pagy/extras/array'
44+
45+
# Calendar extra: Add pagination filtering by calendar time unit (year, quarter, month, week, day)
46+
# See https://ddnexus.github.io/pagy/docs/extras/calendar
47+
# require 'pagy/extras/calendar'
48+
# Default for each unit
49+
# Pagy::Calendar::Year::DEFAULT[:order] = :asc # Time direction of pagination
50+
# Pagy::Calendar::Year::DEFAULT[:format] = '%Y' # strftime format
51+
#
52+
# Pagy::Calendar::Quarter::DEFAULT[:order] = :asc # Time direction of pagination
53+
# Pagy::Calendar::Quarter::DEFAULT[:format] = '%Y-Q%q' # strftime format
54+
#
55+
# Pagy::Calendar::Month::DEFAULT[:order] = :asc # Time direction of pagination
56+
# Pagy::Calendar::Month::DEFAULT[:format] = '%Y-%m' # strftime format
57+
#
58+
# Pagy::Calendar::Week::DEFAULT[:order] = :asc # Time direction of pagination
59+
# Pagy::Calendar::Week::DEFAULT[:format] = '%Y-%W' # strftime format
60+
#
61+
# Pagy::Calendar::Day::DEFAULT[:order] = :asc # Time direction of pagination
62+
# Pagy::Calendar::Day::DEFAULT[:format] = '%Y-%m-%d' # strftime format
63+
#
64+
# Uncomment the following lines, if you need calendar localization without using the I18n extra
65+
# module LocalizePagyCalendar
66+
# def localize(time, opts)
67+
# ::I18n.l(time, **opts)
68+
# end
69+
# end
70+
# Pagy::Calendar.prepend LocalizePagyCalendar
71+
72+
# Countless extra: Paginate without any count, saving one query per rendering
73+
# See https://ddnexus.github.io/pagy/docs/extras/countless
74+
# require 'pagy/extras/countless'
75+
# Pagy::DEFAULT[:countless_minimal] = false # default (eager loading)
76+
77+
# Elasticsearch Rails extra: Paginate `ElasticsearchRails::Results` objects
78+
# See https://ddnexus.github.io/pagy/docs/extras/elasticsearch_rails
79+
# Default :pagy_search method: change only if you use also
80+
# the searchkick or meilisearch extra that defines the same
81+
# Pagy::DEFAULT[:elasticsearch_rails_pagy_search] = :pagy_search
82+
# Default original :search method called internally to do the actual search
83+
# Pagy::DEFAULT[:elasticsearch_rails_search] = :search
84+
# require 'pagy/extras/elasticsearch_rails'
85+
86+
# Headers extra: http response headers (and other helpers) useful for API pagination
87+
# See http://ddnexus.github.io/pagy/extras/headers
88+
require "pagy/extras/headers"
89+
# Pagy::DEFAULT[:headers] = { page: 'Current-Page',
90+
# items: 'Page-Items',
91+
# count: 'Total-Count',
92+
# pages: 'Total-Pages' } # default
93+
94+
# Meilisearch extra: Paginate `Meilisearch` result objects
95+
# See https://ddnexus.github.io/pagy/docs/extras/meilisearch
96+
# Default :pagy_search method: change only if you use also
97+
# the elasticsearch_rails or searchkick extra that define the same method
98+
# Pagy::DEFAULT[:meilisearch_pagy_search] = :pagy_search
99+
# Default original :search method called internally to do the actual search
100+
# Pagy::DEFAULT[:meilisearch_search] = :ms_search
101+
# require 'pagy/extras/meilisearch'
102+
103+
# Metadata extra: Provides the pagination metadata to Javascript frameworks like Vue.js, react.js, etc.
104+
# See https://ddnexus.github.io/pagy/docs/extras/metadata
105+
# you must require the frontend helpers internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels
106+
# require 'pagy/extras/frontend_helpers'
107+
# require 'pagy/extras/metadata'
108+
# For performance reasons, you should explicitly set ONLY the metadata you use in the frontend
109+
# Pagy::DEFAULT[:metadata] = %i[scaffold_url page prev next last] # example
110+
111+
# Searchkick extra: Paginate `Searchkick::Results` objects
112+
# See https://ddnexus.github.io/pagy/docs/extras/searchkick
113+
# Default :pagy_search method: change only if you use also
114+
# the elasticsearch_rails or meilisearch extra that defines the same
115+
# DEFAULT[:searchkick_pagy_search] = :pagy_search
116+
# Default original :search method called internally to do the actual search
117+
# Pagy::DEFAULT[:searchkick_search] = :search
118+
# require 'pagy/extras/searchkick'
119+
# uncomment if you are going to use Searchkick.pagy_search
120+
# Searchkick.extend Pagy::Searchkick
121+
122+
# Frontend Extras
123+
124+
# Bootstrap extra: Add nav, nav_js and combo_nav_js helpers and templates for Bootstrap pagination
125+
# See https://ddnexus.github.io/pagy/docs/extras/bootstrap
126+
# require 'pagy/extras/bootstrap'
127+
128+
# Bulma extra: Add nav, nav_js and combo_nav_js helpers and templates for Bulma pagination
129+
# See https://ddnexus.github.io/pagy/docs/extras/bulma
130+
# require 'pagy/extras/bulma'
131+
132+
# Foundation extra: Add nav, nav_js and combo_nav_js helpers and templates for Foundation pagination
133+
# See https://ddnexus.github.io/pagy/docs/extras/foundation
134+
# require 'pagy/extras/foundation'
135+
136+
# Materialize extra: Add nav, nav_js and combo_nav_js helpers for Materialize pagination
137+
# See https://ddnexus.github.io/pagy/docs/extras/materialize
138+
# require 'pagy/extras/materialize'
139+
140+
# Navs extra: Add nav_js and combo_nav_js javascript helpers
141+
# Notice: the other frontend extras add their own framework-styled versions,
142+
# so require this extra only if you need the unstyled version
143+
# See https://ddnexus.github.io/pagy/docs/extras/navs
144+
# require 'pagy/extras/navs'
145+
146+
# Semantic extra: Add nav, nav_js and combo_nav_js helpers for Semantic UI pagination
147+
# See https://ddnexus.github.io/pagy/docs/extras/semantic
148+
# require 'pagy/extras/semantic'
149+
150+
# UIkit extra: Add nav helper and templates for UIkit pagination
151+
# See https://ddnexus.github.io/pagy/docs/extras/uikit
152+
# require 'pagy/extras/uikit'
153+
154+
# Multi size var used by the *_nav_js helpers
155+
# See https://ddnexus.github.io/pagy/docs/extras/navs#steps
156+
# Pagy::DEFAULT[:steps] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } # example
157+
158+
# Feature Extras
159+
160+
# Gearbox extra: Automatically change the number of items per page depending on the page number
161+
# See https://ddnexus.github.io/pagy/docs/extras/gearbox
162+
# require 'pagy/extras/gearbox'
163+
# set to false only if you want to make :gearbox_extra an opt-in variable
164+
# Pagy::DEFAULT[:gearbox_extra] = false # default true
165+
# Pagy::DEFAULT[:gearbox_items] = [15, 30, 60, 100] # default
166+
167+
# Items extra: Allow the client to request a custom number of items per page with an optional selector UI
168+
# See https://ddnexus.github.io/pagy/docs/extras/items
169+
# require 'pagy/extras/items'
170+
# set to false only if you want to make :items_extra an opt-in variable
171+
# Pagy::DEFAULT[:items_extra] = false # default true
172+
# Pagy::DEFAULT[:items_param] = :items # default
173+
# Pagy::DEFAULT[:max_items] = 100 # default
174+
175+
# Overflow extra: Allow for easy handling of overflowing pages
176+
# See https://ddnexus.github.io/pagy/docs/extras/overflow
177+
# require 'pagy/extras/overflow'
178+
# Pagy::DEFAULT[:overflow] = :empty_page # default (other options: :last_page and :exception)
179+
180+
# Support extra: Extra support for features like: incremental, infinite, auto-scroll pagination
181+
# See https://ddnexus.github.io/pagy/docs/extras/support
182+
# require 'pagy/extras/support'
183+
184+
# Trim extra: Remove the page=1 param from links
185+
# See https://ddnexus.github.io/pagy/docs/extras/trim
186+
# require 'pagy/extras/trim'
187+
# set to false only if you want to make :trim_extra an opt-in variable
188+
# Pagy::DEFAULT[:trim_extra] = false # default true
189+
190+
# Standalone extra: Use pagy in non Rack environment/gem
191+
# See https://ddnexus.github.io/pagy/docs/extras/standalone
192+
# require 'pagy/extras/standalone'
193+
# Pagy::DEFAULT[:url] = 'http://www.example.com/subdir' # optional default
194+
195+
# Rails
196+
# Enable the .js file required by the helpers that use javascript
197+
# (pagy*_nav_js, pagy*_combo_nav_js, and pagy_items_selector_js)
198+
# See https://ddnexus.github.io/pagy/docs/api/javascript
199+
200+
# With the asset pipeline
201+
# Sprockets need to look into the pagy javascripts dir, so add it to the assets paths
202+
# Rails.application.config.assets.paths << Pagy.root.join('javascripts')
203+
204+
# I18n
205+
206+
# Pagy internal I18n: ~18x faster using ~10x less memory than the i18n gem
207+
# See https://ddnexus.github.io/pagy/docs/api/i18n
208+
# Notice: No need to configure anything in this section if your app uses only "en"
209+
# or if you use the i18n extra below
210+
#
211+
# Examples:
212+
# load the "de" built-in locale:
213+
# Pagy::I18n.load(locale: 'de')
214+
#
215+
# load the "de" locale defined in the custom file at :filepath:
216+
# Pagy::I18n.load(locale: 'de', filepath: 'path/to/pagy-de.yml')
217+
#
218+
# load the "de", "en" and "es" built-in locales:
219+
# (the first passed :locale will be used also as the default_locale)
220+
# Pagy::I18n.load({ locale: 'de' },
221+
# { locale: 'en' },
222+
# { locale: 'es' })
223+
#
224+
# load the "en" built-in locale, a custom "es" locale,
225+
# and a totally custom locale complete with a custom :pluralize proc:
226+
# (the first passed :locale will be used also as the default_locale)
227+
# Pagy::I18n.load({ locale: 'en' },
228+
# { locale: 'es', filepath: 'path/to/pagy-es.yml' },
229+
# { locale: 'xyz', # not built-in
230+
# filepath: 'path/to/pagy-xyz.yml',
231+
# pluralize: lambda{ |count| ... } )
232+
233+
# I18n extra: uses the standard i18n gem which is ~18x slower using ~10x more memory
234+
# than the default pagy internal i18n (see above)
235+
# See https://ddnexus.github.io/pagy/docs/extras/i18n
236+
# require 'pagy/extras/i18n'
237+
238+
# Default i18n key
239+
# Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default
240+
241+
# When you are done setting your own default freeze it, so it will not get changed accidentally
242+
Pagy::DEFAULT.freeze

0 commit comments

Comments
 (0)