From ce526600f834707a87fcd9e53c388acba50e74f5 Mon Sep 17 00:00:00 2001 From: PedroAugustoRamalhoDuarte Date: Wed, 20 Nov 2024 09:11:48 -0300 Subject: [PATCH 1/3] upgrade pagy to 9.3.1 --- Gemfile.lock | 4 +- spec/dummy/config/initializers/pagy.rb | 140 +++++++++++-------------- 2 files changed, 62 insertions(+), 82 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index c9b3775..3b7f1d3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - rest-api-generator (0.3.0) + rest-api-generator (0.4.0) anyway_config (>= 2.0.0) pagy rails (>= 5.0) @@ -156,7 +156,7 @@ GEM bigdecimal (>= 3.0) ostruct (>= 0.2) ostruct (0.6.0) - pagy (9.0.5) + pagy (9.3.1) panko_serializer (0.8.2) activesupport oj (> 3.11.0, < 4.0.0) diff --git a/spec/dummy/config/initializers/pagy.rb b/spec/dummy/config/initializers/pagy.rb index 8959c11..58a0d47 100644 --- a/spec/dummy/config/initializers/pagy.rb +++ b/spec/dummy/config/initializers/pagy.rb @@ -2,36 +2,35 @@ require "pagy" -# Pagy initializer file (6.0.1) +# Pagy initializer file (9.3.1) # Customize only what you really need and notice that the core Pagy works also without any of the following lines. # Should you just cherry pick part of this file, please maintain the require-order of the extras -# Pagy DEFAULT Variables + +# Pagy Variables # See https://ddnexus.github.io/pagy/docs/api/pagy#variables -# All the Pagy::DEFAULT are set for all the Pagy instances but can be overridden per instance by just passing them to +# You can set any pagy variable as a Pagy::DEFAULT. They can also be overridden per instance by just passing them to # Pagy.new|Pagy::Countless.new|Pagy::Calendar::*.new or any of the #pagy* controller methods +# Here are the few that make more sense as DEFAULTs: +# Pagy::DEFAULT[:limit] = 20 # default +# Pagy::DEFAULT[:size] = 7 # default +# Pagy::DEFAULT[:ends] = true # default +# Pagy::DEFAULT[:page_param] = :page # default +# Pagy::DEFAULT[:count_args] = [] # example for non AR ORMs +# Pagy::DEFAULT[:max_pages] = 3000 # example -# Instance variables -# See https://ddnexus.github.io/pagy/docs/api/pagy#instance-variables -# Pagy::DEFAULT[:page] = 1 # default -# Pagy::DEFAULT[:items] = 20 # default -# Pagy::DEFAULT[:outset] = 0 # default - -# Other Variables -# See https://ddnexus.github.io/pagy/docs/api/pagy#other-variables -# Pagy::DEFAULT[:size] = [1,4,4,1] # default -# Pagy::DEFAULT[:page_param] = :page # default -# The :params can be also set as a lambda e.g ->(params){ params.exclude('useless').merge!('custom' => 'useful') } -# Pagy::DEFAULT[:params] = {} # default -# Pagy::DEFAULT[:fragment] = '#fragment' # example -# Pagy::DEFAULT[:link_extra] = 'data-remote="true"' # example -# Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default -# Pagy::DEFAULT[:cycle] = true # example -# Pagy::DEFAULT[:request_path] = "/foo" # example # Extras # See https://ddnexus.github.io/pagy/categories/extra + +# Legacy Compatibility Extras + +# Size extra: Enable the Array type for the `:size` variable (e.g. `size: [1,4,4,1]`) +# See https://ddnexus.github.io/pagy/docs/extras/size +# require 'pagy/extras/size' # must be required before the other extras + + # Backend Extras # Arel extra: For better performance utilizing grouped ActiveRecord collections: @@ -45,21 +44,12 @@ # Calendar extra: Add pagination filtering by calendar time unit (year, quarter, month, week, day) # See https://ddnexus.github.io/pagy/docs/extras/calendar # require 'pagy/extras/calendar' -# Default for each unit -# Pagy::Calendar::Year::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Year::DEFAULT[:format] = '%Y' # strftime format -# -# Pagy::Calendar::Quarter::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Quarter::DEFAULT[:format] = '%Y-Q%q' # strftime format -# -# Pagy::Calendar::Month::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Month::DEFAULT[:format] = '%Y-%m' # strftime format -# -# Pagy::Calendar::Week::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Week::DEFAULT[:format] = '%Y-%W' # strftime format -# -# Pagy::Calendar::Day::DEFAULT[:order] = :asc # Time direction of pagination -# Pagy::Calendar::Day::DEFAULT[:format] = '%Y-%m-%d' # strftime format +# Default for each calendar unit class in IRB: +# >> Pagy::Calendar::Year::DEFAULT +# >> Pagy::Calendar::Quarter::DEFAULT +# >> Pagy::Calendar::Month::DEFAULT +# >> Pagy::Calendar::Week::DEFAULT +# >> Pagy::Calendar::Day::DEFAULT # # Uncomment the following lines, if you need calendar localization without using the I18n extra # module LocalizePagyCalendar @@ -84,13 +74,17 @@ # require 'pagy/extras/elasticsearch_rails' # Headers extra: http response headers (and other helpers) useful for API pagination -# See http://ddnexus.github.io/pagy/extras/headers -require "pagy/extras/headers" +# See https://ddnexus.github.io/pagy/docs/extras/headers +require 'pagy/extras/headers' # Pagy::DEFAULT[:headers] = { page: 'Current-Page', -# items: 'Page-Items', +# limit: 'Page-Items', # count: 'Total-Count', # pages: 'Total-Pages' } # default +# Keyset extra: Paginate with the Pagy keyset pagination technique +# See https://ddnexus.github.io/pagy/docs/extras/keyset +# require 'pagy/extras/keyset' + # Meilisearch extra: Paginate `Meilisearch` result objects # See https://ddnexus.github.io/pagy/docs/extras/meilisearch # Default :pagy_search method: change only if you use also @@ -102,8 +96,8 @@ # Metadata extra: Provides the pagination metadata to Javascript frameworks like Vue.js, react.js, etc. # See https://ddnexus.github.io/pagy/docs/extras/metadata -# you must require the frontend helpers internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels -# require 'pagy/extras/frontend_helpers' +# you must require the JS Tools internal extra (BEFORE the metadata extra) ONLY if you need also the :sequels +# require 'pagy/extras/js_tools' # require 'pagy/extras/metadata' # For performance reasons, you should explicitly set ONLY the metadata you use in the frontend # Pagy::DEFAULT[:metadata] = %i[scaffold_url page prev next last] # example @@ -112,13 +106,14 @@ # See https://ddnexus.github.io/pagy/docs/extras/searchkick # Default :pagy_search method: change only if you use also # the elasticsearch_rails or meilisearch extra that defines the same -# DEFAULT[:searchkick_pagy_search] = :pagy_search +# Pagy::DEFAULT[:searchkick_pagy_search] = :pagy_search # Default original :search method called internally to do the actual search # Pagy::DEFAULT[:searchkick_search] = :search # require 'pagy/extras/searchkick' # uncomment if you are going to use Searchkick.pagy_search # Searchkick.extend Pagy::Searchkick + # Frontend Extras # Bootstrap extra: Add nav, nav_js and combo_nav_js helpers and templates for Bootstrap pagination @@ -129,58 +124,38 @@ # See https://ddnexus.github.io/pagy/docs/extras/bulma # require 'pagy/extras/bulma' -# Foundation extra: Add nav, nav_js and combo_nav_js helpers and templates for Foundation pagination -# See https://ddnexus.github.io/pagy/docs/extras/foundation -# require 'pagy/extras/foundation' - -# Materialize extra: Add nav, nav_js and combo_nav_js helpers for Materialize pagination -# See https://ddnexus.github.io/pagy/docs/extras/materialize -# require 'pagy/extras/materialize' - -# Navs extra: Add nav_js and combo_nav_js javascript helpers -# Notice: the other frontend extras add their own framework-styled versions, -# so require this extra only if you need the unstyled version -# See https://ddnexus.github.io/pagy/docs/extras/navs -# require 'pagy/extras/navs' - -# Semantic extra: Add nav, nav_js and combo_nav_js helpers for Semantic UI pagination -# See https://ddnexus.github.io/pagy/docs/extras/semantic -# require 'pagy/extras/semantic' - -# UIkit extra: Add nav helper and templates for UIkit pagination -# See https://ddnexus.github.io/pagy/docs/extras/uikit -# require 'pagy/extras/uikit' +# Pagy extra: Add the pagy styled versions of the javascript-powered navs +# and a few other components to the Pagy::Frontend module. +# See https://ddnexus.github.io/pagy/docs/extras/pagy +# require 'pagy/extras/pagy' # Multi size var used by the *_nav_js helpers -# See https://ddnexus.github.io/pagy/docs/extras/navs#steps -# Pagy::DEFAULT[:steps] = { 0 => [2,3,3,2], 540 => [3,5,5,3], 720 => [5,7,7,5] } # example +# See https://ddnexus.github.io/pagy/docs/extras/pagy#steps +# Pagy::DEFAULT[:steps] = { 0 => 5, 540 => 7, 720 => 9 } # example + # Feature Extras -# Gearbox extra: Automatically change the number of items per page depending on the page number +# Gearbox extra: Automatically change the limit per page depending on the page number # See https://ddnexus.github.io/pagy/docs/extras/gearbox # require 'pagy/extras/gearbox' # set to false only if you want to make :gearbox_extra an opt-in variable # Pagy::DEFAULT[:gearbox_extra] = false # default true -# Pagy::DEFAULT[:gearbox_items] = [15, 30, 60, 100] # default +# Pagy::DEFAULT[:gearbox_limit] = [15, 30, 60, 100] # default -# Items extra: Allow the client to request a custom number of items per page with an optional selector UI -# See https://ddnexus.github.io/pagy/docs/extras/items -# require 'pagy/extras/items' -# set to false only if you want to make :items_extra an opt-in variable -# Pagy::DEFAULT[:items_extra] = false # default true -# Pagy::DEFAULT[:items_param] = :items # default -# Pagy::DEFAULT[:max_items] = 100 # default +# Limit extra: Allow the client to request a custom limit per page with an optional selector UI +# See https://ddnexus.github.io/pagy/docs/extras/limit +require 'pagy/extras/limit' +# set to false only if you want to make :limit_extra an opt-in variable +# Pagy::DEFAULT[:limit_extra] = false # default true +# Pagy::DEFAULT[:limit_param] = :limit # default +# Pagy::DEFAULT[:limit_max] = 100 # default # Overflow extra: Allow for easy handling of overflowing pages # See https://ddnexus.github.io/pagy/docs/extras/overflow # require 'pagy/extras/overflow' # Pagy::DEFAULT[:overflow] = :empty_page # default (other options: :last_page and :exception) -# Support extra: Extra support for features like: incremental, infinite, auto-scroll pagination -# See https://ddnexus.github.io/pagy/docs/extras/support -# require 'pagy/extras/support' - # Trim extra: Remove the page=1 param from links # See https://ddnexus.github.io/pagy/docs/extras/trim # require 'pagy/extras/trim' @@ -192,9 +167,15 @@ # require 'pagy/extras/standalone' # Pagy::DEFAULT[:url] = 'http://www.example.com/subdir' # optional default +# Jsonapi extra: Implements JSON:API specifications +# See https://ddnexus.github.io/pagy/docs/extras/jsonapi +# require 'pagy/extras/jsonapi' # must be required after the other extras +# set to false only if you want to make :jsonapi an opt-in variable +# Pagy::DEFAULT[:jsonapi] = false # default true + # Rails # Enable the .js file required by the helpers that use javascript -# (pagy*_nav_js, pagy*_combo_nav_js, and pagy_items_selector_js) +# (pagy*_nav_js, pagy*_combo_nav_js, and pagy_limit_selector_js) # See https://ddnexus.github.io/pagy/docs/api/javascript # With the asset pipeline @@ -230,13 +211,12 @@ # filepath: 'path/to/pagy-xyz.yml', # pluralize: lambda{ |count| ... } ) + # I18n extra: uses the standard i18n gem which is ~18x slower using ~10x more memory # than the default pagy internal i18n (see above) # See https://ddnexus.github.io/pagy/docs/extras/i18n # require 'pagy/extras/i18n' -# Default i18n key -# Pagy::DEFAULT[:i18n_key] = 'pagy.item_name' # default # When you are done setting your own default freeze it, so it will not get changed accidentally Pagy::DEFAULT.freeze From c37a94fc8789c0681025f7a242523081e7c7bb17 Mon Sep 17 00:00:00 2001 From: PedroAugustoRamalhoDuarte Date: Wed, 20 Nov 2024 09:12:14 -0300 Subject: [PATCH 2/3] testing pagination better --- spec/dummy/app/controllers/cars_controller.rb | 4 ++++ spec/dummy/config/initializers/pagy.rb | 12 ++---------- .../resource_controller_spec.rb | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/spec/dummy/app/controllers/cars_controller.rb b/spec/dummy/app/controllers/cars_controller.rb index a10371a..49b9ac3 100644 --- a/spec/dummy/app/controllers/cars_controller.rb +++ b/spec/dummy/app/controllers/cars_controller.rb @@ -13,4 +13,8 @@ def authorize_logic # Custom authorization logic # authorize! :manage, @resource end + + def pagination + true + end end diff --git a/spec/dummy/config/initializers/pagy.rb b/spec/dummy/config/initializers/pagy.rb index 58a0d47..a10747f 100644 --- a/spec/dummy/config/initializers/pagy.rb +++ b/spec/dummy/config/initializers/pagy.rb @@ -6,7 +6,6 @@ # Customize only what you really need and notice that the core Pagy works also without any of the following lines. # Should you just cherry pick part of this file, please maintain the require-order of the extras - # Pagy Variables # See https://ddnexus.github.io/pagy/docs/api/pagy#variables # You can set any pagy variable as a Pagy::DEFAULT. They can also be overridden per instance by just passing them to @@ -19,18 +18,15 @@ # Pagy::DEFAULT[:count_args] = [] # example for non AR ORMs # Pagy::DEFAULT[:max_pages] = 3000 # example - # Extras # See https://ddnexus.github.io/pagy/categories/extra - # Legacy Compatibility Extras # Size extra: Enable the Array type for the `:size` variable (e.g. `size: [1,4,4,1]`) # See https://ddnexus.github.io/pagy/docs/extras/size # require 'pagy/extras/size' # must be required before the other extras - # Backend Extras # Arel extra: For better performance utilizing grouped ActiveRecord collections: @@ -75,7 +71,7 @@ # Headers extra: http response headers (and other helpers) useful for API pagination # See https://ddnexus.github.io/pagy/docs/extras/headers -require 'pagy/extras/headers' +require "pagy/extras/headers" # Pagy::DEFAULT[:headers] = { page: 'Current-Page', # limit: 'Page-Items', # count: 'Total-Count', @@ -113,7 +109,6 @@ # uncomment if you are going to use Searchkick.pagy_search # Searchkick.extend Pagy::Searchkick - # Frontend Extras # Bootstrap extra: Add nav, nav_js and combo_nav_js helpers and templates for Bootstrap pagination @@ -133,7 +128,6 @@ # See https://ddnexus.github.io/pagy/docs/extras/pagy#steps # Pagy::DEFAULT[:steps] = { 0 => 5, 540 => 7, 720 => 9 } # example - # Feature Extras # Gearbox extra: Automatically change the limit per page depending on the page number @@ -145,7 +139,7 @@ # Limit extra: Allow the client to request a custom limit per page with an optional selector UI # See https://ddnexus.github.io/pagy/docs/extras/limit -require 'pagy/extras/limit' +require "pagy/extras/limit" # set to false only if you want to make :limit_extra an opt-in variable # Pagy::DEFAULT[:limit_extra] = false # default true # Pagy::DEFAULT[:limit_param] = :limit # default @@ -211,12 +205,10 @@ # filepath: 'path/to/pagy-xyz.yml', # pluralize: lambda{ |count| ... } ) - # I18n extra: uses the standard i18n gem which is ~18x slower using ~10x more memory # than the default pagy internal i18n (see above) # See https://ddnexus.github.io/pagy/docs/extras/i18n # require 'pagy/extras/i18n' - # When you are done setting your own default freeze it, so it will not get changed accidentally Pagy::DEFAULT.freeze diff --git a/spec/lib/rest_api_generator/resource_controller_spec.rb b/spec/lib/rest_api_generator/resource_controller_spec.rb index 9c39ad7..040c45d 100644 --- a/spec/lib/rest_api_generator/resource_controller_spec.rb +++ b/spec/lib/rest_api_generator/resource_controller_spec.rb @@ -150,4 +150,22 @@ end end end + + describe "pagination" do + context "when pagination is enabled" do + it "returns pagy headers" do + Car.create! + get "/cars" + expect(response.headers["Total-Count"]).to eq("1") + end + end + + describe "limit" do + it "returns 10 records" do + 11.times { Car.create! } + get "/cars", params: { limit: 10 } + expect(JSON.parse(response.body).length).to eq(10) + end + end + end end From 89c5c8ae86772a8090b5f757c40ea181bf350f59 Mon Sep 17 00:00:00 2001 From: PedroAugustoRamalhoDuarte Date: Wed, 20 Nov 2024 09:26:44 -0300 Subject: [PATCH 3/3] improves pagination docs --- docs/features/pagination.md | 49 ++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/docs/features/pagination.md b/docs/features/pagination.md index 84488c8..ece53a0 100644 --- a/docs/features/pagination.md +++ b/docs/features/pagination.md @@ -9,6 +9,9 @@ Next, you should add some lines on top of the previously created pagy file: # config/initializers/pagy.rb require "pagy" require "pagy/extras/headers" + +# If you need limit the number of items per page dynamically +require "pagy/extras/limit" ``` At last, change the pagination variable on RestApiGenerator initializer to true; @@ -25,4 +28,48 @@ Note, if the parent controller is changed, it is necessary to include Pagy::Back class NewParentController < ActionController::Base include Pagy::Backend end -``` \ No newline at end of file +``` + +## Usage + +This API uses pagination in compliance with [RFC-8288](https://www.rfc-editor.org/rfc/rfc8288), which allows for clear +navigation through paginated data using response headers. + +### Response Headers + +The pagination details are included in the response headers, which may look like the following example: + +```http +link: ; rel="first", + ; rel="prev", + ; rel="next", + ; rel="last" +current-page: 3 +page-items: 20 +total-pages: 50 +total-count: 1000 +``` + +- **`link`**: Contains URLs for navigation, indicating the first, previous, next, and last pages. +- **`current-page`**: The current page number. +- **`page-items`**: The number of items displayed per page. +- **`total-pages`**: The total number of pages available. +- **`total-count`**: The total number of items in the collection. + +For additional details, refer to the [Pagy headers documentation](https://ddnexus.github.io/pagy/docs/extras/headers/). + +--- + +### Limiting the Number of Items Per Page + +> **Note:** To use the dynamic limit feature, you need to configure Pagy as per the [Pagy limit documentation](https://ddnexus.github.io/pagy/docs/extras/limit/). + +You can dynamically control the number of items displayed per page by using the **limit extra** feature. + +#### Example: + +```http +GET /cars?limit=10 +``` + +In the above example, the API will return up to 10 items per page.