Technical Documentation: ddnexus/pagy
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (`README.md`)
Pagy the leaping gem!
Agnostic pagination in plain Ruby
[!TIP]
⭐ If you like Pagy, please support it with a Star! ⭐
💚 v3 was already quite snappy...
... and now it's more, with less.
- Compatible with all environments and collection types
- It can use OFFSET, COUNTISH, COUNTLESS, KEYSET, KEYNAV, SEARCH, and CALENDAR pagination techniques
- It supports server-side rendering or faster client-side rendering for popular CSS frameworks and APIs
- It autoloads ONLY the methods that you actually use, with almost zero configuration
- It boasts 100% test coverage for Ruby, HTML, and JavaScript end-to-end (E2E)
💚 Examples
Pagination code
# Include pagy in your code (usually application_controller.rb)
include Pagy::Method
# Offset-based pagination
@pagy, @records = pagy(:offset, Product.all)
# Keyset-based pagination (fastest technique)
@pagy, @records = pagy(:keyset, Product.order(my_order).all)
# Paginate your collection with one of several paginators
@pagy, @records = pagy(...)See all the available paginators
JSON:API pagination
# JSON:API nested query string. E.g.: ?page[number]=2&page[size]=100
@pagy, @records = pagy(:offset, Product.all, jsonapi: true)
@pagy, @records = pagy(:keyset, Product.order(my_order).all, jsonapi: true)
render json: { links: @pagy.urls_hash, data: @records }JSON-client pagination
render json: { pagy: @pagy.data_hash, data: @records }Search server pagination
Available paginators: :elasticsearch_rails, :meilisearch, :rails_active_search, :searchkick, :typesense_rails
# Extend your models (e.g. application_record.rb)
extend Pagy::Search
# Paginate with pagy:
search = Product.pagy_search(params[:q])
@pagy, @response = pagy(:a_search_paginator, search)
# Or get pagy from paginated results:
@results = Product.search(params[:q])
@pagy = pagy(:a_search_paginator, @results)Calendar pagination
Combine time-range and offset pagination.
(Available time units: year, quarter, month, week, and day)
@calendar, @pagy, @records = pagy(:calendar, collection, year: {}, month: {}, offset: {})<%== @calendar[:year].series_nav(:bootstrap) %>
<%== @calendar[:month].series_nav(:bootstrap) %>
<%== @pagy.info_tag %>
...
<%== @pagy.series_nav(:bootstrap) %>Server side rendering
`series_nav`
Default :pagy, :bootstrap and :bulma styles shown.
<%== @pagy.series_nav %>
<%== @pagy.series_nav(:bootstrap) %>
<%== @pagy.series_nav(:bulma) %>Client side rendering
# pagy.rb initializer
javascript_dir = Rails.root.join('app/javascript')
Pagy.sync_javascript(javascript_dir, 'pagy.mjs') if Rails.env.development?`series_nav_js`
Faster and responsive
Dynamically fills the container width.
<%== @pagy.series_nav_js %>
<%== @pagy.series_nav_js(:bootstrap) %>
<%== @pagy.series_nav_js(:bulma) %>`input_nav_js`
Fastest! Combines navigation and info in minimum space.
<%== @pagy.input_nav_js %>
<%== @pagy.input_nav_js(:bootstrap) %>
<%== @pagy.input_nav_js(:bulma) %>💚 Dev Tools
Integrate pagy with your app's themes interactively (watch demo), and ask specific questions to the Pagy AI right in your app! You need only a single line in your page/layout head to get the Pagy Wand and the Pagy AI:
<%== Pagy.dev_tools %>See Dev Tools
💚 Support and Docs
- Quick Start
- How To (quick recipes)
- Upgrade to 43 (from version 9 or earlier)
- Migrate from WillPaginate and Kaminari (practical guide)
- Discussions
- Issues
- Changelog
[!TIP]
⭐ If you like Pagy, please support it with a Star! ⭐
Top 🏆 Adopters
…and 13,500+ more public repos on GitHub.
Top 💯 Contributors
💚 Credits
Special thanks to:
- JetBrains for their free open source license.
- Ben Koshy for his contributions to the documentation, user support and interaction with external frameworks.
- The Stargazers for their support.
💚 Repository Info
How to contribute
See Contributing
Versioning
- Pagy follows the Semantic Versioning 2.0.0. Please check the Changelog for breaking changes introduced by major versions. Using pessimistic version constraint in your Gemfile will ensure smooth upgrades.
Branches
- The
masterbranch is the latest rubygem-published release. It also contains docs and comment changes that don't affect the published code. It is never force-pushed. - The
devbranch is the development branch with the new code that will be merged in the next release. It could be force-pushed. - Expect any other branch to be internal, experimental, force-pushed, rebased and/or deleted even without merging.
💚 License
Overview (`test/README.md`)
Ruby Test Environment
Ruby is tested with minitest through thor. It also uses holdify as a snapshot system.
Prerequisite
- Install the gems:
bundle install - E2E tests use your local Chrome
No other setup required.
Testing
❯ bundle exec thor list
test
----
thor test:all # Test Rubocop + API + Coverage + E2E
thor test:api:all # Test current and next API
thor test:api:coverage # Test API coverage
thor test:api:current # Test current API
thor test:api:next # Test next API
thor test:e2e:apps [APP] # Test all E2E apps (or just APP)Run all checks
To get green light for PRs, just run them all in ~10secs...
bundle exec thor test:all
Overview (`scripts/hooks/README.md`)
Git Hooks
A hook to ensure consistency and automation. Please setup the hook if you contribute to pagy with PRs.
See also the brief description inside the hook file.
Setup
Symlink
If your system support symlinks: symlink the hook into the .git/hooks dir:
# from the repo root
ln -s ../../scripts/hooks/pre-commit .git/hooksCopy
Only for filesystem that don't support symlinks: copy the hooks into the .git/hooks dir:
# from the repo root
cp scripts/hooks/pre-commit .git/hooksCHANGELOG (`docs/CHANGELOG.md`)
icon: versions
:icon-versions: CHANGELOG
Release Policy
Pagy follows the Semantic Versioning 2.0.0, and introduces BREAKING CHANGES only for MAJOR versions.
We release any new version (MAJOR, MINOR, PATCH) as soon as it is ready for release, regardless of any time constraint, frequency
or duration.
We rarely deprecate elements (releasing a new MAJOR version is just simpler and more efficient). However, when we do, you can
expect the old/deprecated functionality to be supported ONLY during the current MAJOR version.
Recommended Version Constraint
Given a version number MAJOR.MINOR.PATCH (e.g. 43.8.1):
The gem 'pagy', '~> 43.0' Gemfile entry (without the PATCH number) ensures that the bundle update command will update pagy to
the most recent version WITHOUT BREAKING CHANGES.
Increment the MAJOR version in your Gemfile ONLY when you are ready to handle the BREAKING CHANGES.
Breaking Changes
Follow the Upgrade to 43 Guide.
If you upgrade from version < 9.0.0 see the following:
- Breaking changes in version 9.0.0
- Breaking changes in version 8.0.0
- Breaking changes in version 7.0.0
- Breaking changes in version 6.0.0
- Breaking changes in version 5.0.0
- Breaking changes in version 4.0.0
- Breaking changes in version 3.0.0
- Breaking changes in version 2.0.0
- Breaking changes in version 1.0.0
[!TIP]
If you need to update through multiple versions, reimplementing the updated pagination
from scratch might be faster.
Deprecations
Pagy.options: UsePagy::OPTIONSdirectly.Pagy.sync_javascript(...): UsePagy.sync(:javascript, ...)instead.:max_pagesoption: follow this method instead.
IMPORTANT: The Issue #890 still affect the:max_pagesoption, so stop using it ASAP.:client_max_limitand:max_limitoptions: use:client_limitinstead.
Version 43.8.1
- Fix Active Record connection checkout in keyset pagination (#931)
Version 43.8.0
- Add Romanian localization (#930)
Version 43.7.1
- Fix the database error on an out-of-range page with a huge page number (#929)
Version 43.7.0
- Refactor the Search::Arguments and Searcher classes to allow more flexibility in chaining queres.
- Fix the non-standard "previous" link relation in headers_hash and JSON:API urls_hash
- headers_hash emits the conventional rel="prev" in the link header
- urls_hash returns the :prev key with jsonapi: true, as the JSON:API specification requires
- urls_hash keeps the :previous key otherwise
- Fix series_nav_js ignoring the :slots and :compact helper options
- The :slots and :compact options passed to the series_nav_js helpers were silently ignored
- The :steps option overrides the :slots option, while the :compact option applies to all the steps
- Fix the playground doc URLs and make the playground apps consistent
- Add :rails_active_search paginator, test and docs
Version 43.6.3
- Deprecate the :max_limit in favor of the more descriptive :client_limit option.
Version 43.6.2
- Fix nil records returned for Array collections on page overflow (#920) (Fix #919)
Version 43.6.1
- HTML escape URL strings in href attributes (Fix #914)
Version 43.6.0
- Add the max_result_window option to the searchkick and elasticsearch_rails paginators to get an accurate count (#910)
Version 43.5.6
- Validate I18n locale input, coerce dev_tools wand_scale, add input-safety docs (#908)
- Coerce dev_tools wand_scale to a float
- Validate the I18n locale against a BCP 47 pattern
- Update docs and comments about safety
Version 43.5.5
- Rescue malformed page request param in Pagy::Keyset and KeynavJsPaginator (#907)
- Rescue malformed page request param in Pagy::Keyset and KeynavJsPaginator
- Simplify decoding logic
Version 43.5.4
- Fix SERIES_SLOTS loading error (close #902)
Version 43.5.3
- Autoload series, a_lambda and page_label
- Add Hungarian localization file for Pagy (#896)
Version 43.5.2
- Add type validation for page and limit keys type (close #895)
- Simplify series_nav_js removing "pagy-rjs" CSS class (Fix #894)
Version 43.5.1
- Remove ghost code from cli; improve tests
Version 43.5.0
- Update javascripts according to es-linting
- Update min ruby version to 3.3 (remove EOL 3.2)
- Implement the NEW
pagy/nextentrypoint to run the NEXT version now - Refactor deprecations:
- Deprecated :client_max_limit in favor of :max_limit; moved code into deprecation.rb
- Move deprecated options out of class code, to keep the code clean
- Remove RBS resources. Not worth the maintenance effort.
Version 43.4.4
- Make typecasting in Keyset based classes safer and more efficient
Version 43.4.3
- Deprecate the :max_pages option (close #890)
Version 43.4.2
- Fix edge-case for queries with multiple orderings on same column (#888)
Version 43.4.1
- Normalize deprecations
Version 43.4.0
- Improve stylesheets and docs
- Improve JavaScript:
- Add sync method and task
- Deprecate sync_javascript
- Simplify build, configuration and docs
Version 43.3.3
- Fix Request#resolve_page with jsonapi, limit, and missing page param (#885)
- Fix pagy-tailwind.css inconsistencies
- Improve ts/js build process and wand help
- Move the next_tag into the Pagy class
Version 43.3.2
- Implement NumericUI module to avoid including the numeric helpers in keynav classes
- Improve offset accessors and update docs
- Add basic RBS
Version 43.3.1
- Update assets for a few apps
- Fix pagy.ts /.js input_nav update
Version 43.3.0
- Add :typesense_rails paginator (See typesense/typesense-rails#17)
- Accept a variable number of search arguments
- Improve resilience of internal pagy nav method
- Use Pagy::OPTIONS instead of Pagy.options for efficiency
- Simplify assign options
Version 43.2.10
- Add failing test and revert code that caused empty aria label
- Avoid invalid limit param (similar to #862)
- Add thread flag to /bin/pagy
- Add uri gem dependency to the gemspec
- Freeze the @order in key* apps
- Replace require with require_relative in Pagy::CLI
- Make Pagy::OPTIONS thread-safe
Version 43.2.9
- Fix NoMethodError with tampered params (#872)
Version 43.2.8
- Add fallback to 'en' for unknown locale. Implement #868.
- Fix resolve_page with empty page in classes with non-integer page. Close #863
- Simplify keyset syntax
Version 43.2.7
- Add a hint predicate for DB optimizers, to multi-column keysets
- Improve code readability and style
- Refactor anchor tag helpers
Version 43.2.6
- Refactor i18n:
- Raise exceptions for missing 'pagy' and 'p11n' keys in the dictionary
file - Improve efficiency and readability
- Raise exceptions for missing 'pagy' and 'p11n' keys in the dictionary
Version 43.2.5
- Fix Pagy::I18n.locale to ensure to_s. Close #861.
- Reduce endless methods to very short, paramless ones
- Refactor the in_range? method:
- Remove implicit assignation to empty page variable
- Enforce freezing the Pagy::Request object and params
- Refactor calendar:
- Remove the marshaling
- Improve use and naming of locals
- Improve readability
- Refactor linkable:
- Improve use of locals
- Extend conditional sub to fragment
- Improve readability
- Improve simplicity and readability
Version 43.2.4
- Fix anchor_string option not being read from @options in a_lambda. Close #857
- Fix page '0' raising an exception
Version 43.2.3
- Remove rerun
- Improved direction handling in CSSs
Version 43.2.2
- Refactor bin/pagy to use the Pagy::CLI class
- Replace optimist with the optparse standard lib
- Simplify apps by using SQLite :memory:
Version 43.2.1
- Fix the shallow cloning of root_key params. Close #851.
- Implements support for easy overriding
- Add :current_url alias to :page_url
- Fix limit_tag_js not respecting the passed :client_max_limit option
- Fix data_hash returning keys with nil values, or URLs without page; add :current_url alias to :page_url
- Remove warning when fit_time
- Fix respond_to_missing definition arguments in Search::Arguments
Version 43.2.0
- Implement :countish paginator
- Simplify Pagy::Linkable
Version 43.1.8
- Refactoring of elasticsearch_rails paginator:
- Fix "response" shadowing. Close #842.
- Simplify code
- Improve readability: rename variables and methods in more natural
and unambiguous language
Version 43.1.7
- Fix and improve search paginators:
- Add support for elasticsearch_rails v8
- Prioritize elasticsearch_rails response over raw_response in
total_count (causing multiple query executions) - Fix the ignored :search_method paginator option
- Close #837, close #838, close #839.
Version 43.1.6
- Ensure the request GET and POST merge into a proper params Hash
- Simplify code efficiency and readability
Version 43.1.5
- Fix and improve the composition of the page url. Close #835
Version 43.1.4
- Add full support for legacy countless params, url composition and (limited) behavior
Version 43.1.3
- Improve the page options handling for countless:
- Replace the crippled handling of legacy last-less links params
introduced in 43.1.2 by gracefully starting the pagination from
the beginning - Remove the compose_page_param method (it would need a deep refactoring
for compatibility with the legacy handling) - Improve testing
- Replace the crippled handling of legacy last-less links params
- Improve the info message for empty collection in countless paginations
Version 43.1.2
- Support easy countless page param overriding (for legacy param and behavior). See #816
- Handle legacy page param for :countless paginator. Close #832
- Improve mock collections
- Improve code comments
Version 43.1.1
- Makes keynav pagination compatible with nested params:
- Improve the URL composing and unescaping
- Adds the keynav+root_key.ru showcase app
- Simplify the request code and arguments
Version 43.1.0
- Translate the aria_label.nav entry in the id, ja, kn, sw locales. Close #588, close #590, close #591, close #603.
- Improve the Pagy AI panel
- Simplify the paginators code
- Allow nested :page and :limit request params and URLs:
- Add the :root_key option:
- Simplify the :jsonapi handling as a special case of nested params
- Fix and simplify the pagy console code
Version 43.0.7
- Add compatibility for searchkick 6. Close #831
- Fix the search paginators request in passive mode. Close #830.
Version 43.0.6
- Improve Pagy AI Widget scripts
Version 43.0.5
- Add console loader for easier usage
- Add comment for the calendar usage. Close #827.
Version 43.0.4
- Remove the Pagy::OPTIONS from the Calendar configuration. Close #825
Version 43.0.3
- Update tr.yml (#824)
Version 43.0.2
- Ensure the Pagy::Request#params are the original params sent with the request. Close #821
Version 43.0.1
- Reimplement reading params from POST requests; rename internal variables. Close #821
- Fix AI widget problem for apps. Close #817.
- Improve I18n documentation. Close #811
- Link to documentation website's CHANGELOG page (#804)
Version 43.0.0
We needed a leap version to unequivocally signal that it's not just a major version: it's a complete redesign of the legacy
code at all levels, usage and API included.
Why 43? Because it's exactly one step beyond "The answer to the ultimate question of life, the Universe, and everything." 😉
Changes
- The Countless pagination remembers the last page
- Pagination navs now allow jumping forward after navigating back a few pages.
- Javascript refactoring
- The new
Pagy.sync_javascriptfunction used in thepagy.jsinitializer, avoids complicated configurations. - Added the plain
pagy.jsand relative source map files.
- The new
- I18n refactoring
- No setup required: the locales and their pluralization are autoloaded when your app uses them.
- The locale files are easier to override with
Pagy::I18n.pathnames << my_dictionaries.
- HTML and CSS refactoring
- Stylesheets are now based on CSS properties and calculations, for easier customization.
- The new PagyWand interactive tool generates the CSS Override for your custom styles and provides live feedback right in your
app.
- Playground apps
- Better usability and styles
- Bootstrap and Bulma
- Fixed a few style glitches.
CHANGELOG LEGACY (`docs/CHANGELOG_LEGACY.md`)
icon: versions layout: page visibility: hidden
LEGACY CHANGELOG
[!WARNING]
Many links on this page may refer to old resources and may return HTTP 404 "Not Found"
Version 9.3.4
- Fix method visibility in JsonApiExtra (#765)
Version 9.3.3
- Add test for locales - to find problematic keys (#752)
- Update locales: zh-CN, zh-HK, zh-TW (#751) (fix #608, fix #609, fix #610)
- Remove :other from :aria_label key and code comment
- Change :item_name which had :one_other keys to default to the :other key
- Fix comment
Version 9.3.2
- Improve gapped series computation by a few milliseconds
Version 9.3.1
- Added qualified column names to the keyset query
Version 9.3.0
- Remove the :typecast_latest variable
- Add the :jsonify_keyset_attributes variable to override the encoding (#749)
Version 9.2.2
- Replace inline templates with template block in sinatra apps
- Replace the rails calendar app with a sinatra app
- Add PagyApps::INDEX
Version 9.2.1
- Improve bin/pagy to dynamically find apps and descriptions
- Apps refactoring:
- Update rails to 8.0
- Replace rails AR keyset apps with sinatra apps
- Improve consistency
Version 9.2.0
- Simplify the keyset API:
- Deprecate the :after_latest variable in favour of :filter_newest
- Add the keyset argument to the :filter_newest lambda
- Rename protected after_latest_query > filter_newest_query
Version 9.1.1
- Simplify calendar code
Version 9.1.0
- Add Dzongkha (dz locale) (#741)
Version 9.0.9
- Set freeze flag to false (#737)
- Fix: Prefix DEFAULT with Pagy:: (#736)
Version 9.0.8
- Keep offset and limit variables untouched by the overflow extra in :empty_page mode (closes #733)
Version 9.0.7
- Absolutize generic define? to fix module resolution
Version 9.0.6
- Fix docs (closes #732)
- Replace pluck with pick
Version 9.0.5
- Fix for missing variables passed to pagy_anchor from pagy_nav (closes #728)
Version 9.0.4
- Fix groupdate timezone error on certain machines/config
- Fix gem containing tmp files
Version 9.0.3
- Remove legacy and unused javascript files
- Improve pagy_get_page with force_integer option
- Fix jsonapi with keyset
- Complete the internal refactoring of version 9:
- Remove the pagy*_get_vars methods now useless
- Use to_i on the page variable for the search extras
Version 9.0.2
- Rename and document the link header to pagy_link_header
- Add first and next url helpers to the keyset extra; add the keyset section to config/pagy.rb
- Fix nil page in keyset URL not overriding the params page
- Extracted shared method
Version 9.0.1
- Fix countless executing the count query
- Rename row_comparison > tuple_comparison; ignore mixed orders
Version 9.0.0
Breaking Changes
Dropped support for deprecated stuff
- The
foundation,materialize,semanticanduikitCSS extras have been removed:
(See the reasons) - Javascript renamed files
pagy.js: usepagy.min.jspagy-module.js: usepagy.mjspagy-dev.js: use thepagy.min.jswith thepagy.min.js.mappagy-module.d.ts: usepagy.d.ts
- The Array type for the
:size(e.g.size: [1, 4, 4, 1]) that generates the classic bar is not supported anymore: use the:sizeset to an integer with theends: truevariable (which are the default since 8.4.6). If a legacy bar remains REALLY a
requirement, addrequire 'pagy/extras/sizeto yourpagy.rbinitalizer. (See the
size extra)
Simple renaming
We used items for too many things that confused even maintainers. The "items" are now referencing only the records/elements
fetched from a collection (plural entity), so they are kept as before (e.g. pagy_*get_items methods). The "number of items" (
singular entity), are now unmistakably referenced as the limit everywhere (code, API, files, extras, docs, etc.). The logic
didn't change so you have just to globally search 'items' and replace with limit and you should be done... or use the detailed
table below:
| Type | Search | Replace |
|---|---|---|
| Pagy Variable | :items |
:limit |
| Extra Path | pagy/extras/items |
pagy/extras/limit |
| Extra Variable | :items_param |
:limit_param |
| Default URL param | items |
limit |
| Extra Variable | :items_extra |
:limit_extra |
| Extra Variable | :max_items |
:limit_max (now inverted) |
| Extra Method | pagy_items_selector_js |
pagy_limit_selector_js |
| Extra Variable | :headers[:items] |
:headers[limit] |
Code changes
- The
DEFAULT[:anchor_string]was useless and has been dropped. - The
:anchor_stringand the:fragmentare not instance variables anymore, but keyword arguments for all the helpers, because
it is frontend code (see the discussion). Instead of passing them to thepagy*method in the controller, pass it to anypagy_*navmethod in the view. - A general internal revamp has changed the positional argument for the Pagy::* objects and constructors methods to keyword
arguments. If you get awrong number of arguments (given 1, expected 0) (ArgumentError), just use a double splat**.
Possibly breaking overrides
- The internal Pagy protected methods have been renamed and refactored. If you use custom Pagy classes, you may need to search
into the code.
Changes
- Improve Keyset::Sequel and docs
- BREAKING: Rename :max_limit > :limit_max
- BREAKING: Rename variable, param, accessor, extra and helper "items" to "limit"
- Add playground keyset_ar.ru and keyset_s.ru apps and integration with the rest of the gems
- Add keyset pagination base files
- Pagy::Keyset API
- ActiveRecord and Sequel adapters
- BREAKING: Transform the vars positional hash argument in keyword arguments (double splat); internal renaming of setup/assign
methods - Refactor pagy_get_vars in various backend extras
- BREAKING: Refactor the fragment url
- BREAKING: Refactor the anchor_string system
- BREAKING: Drop the support for 8+ deprecations
Version 8.6.3
- Add missing DEFAULT[:max_pages] hint to the config/pagy.rb
- Improve activerecord handling in playground apps
- Fix the missing "ar.pagy.aria_label.nav.other" (closes #577)
Version 8.6.2
- Fix the legacy size in code and test
- Improve code readability and size check in series
- Fix the old terminology in the demo.ru app
Version 8.6.1
- Update playground apps and e2e tests
- Update pagy.rb initializer
Version 8.6.0
- Add translated pluralized aria_label.nav for "ar" locale (close #577)
- Deprecate the legacy bar. Insert first and last pages and gaps when needed into the simple bar
Version 8.5.0
- Improve pagy playground launcher
- Refactor calendar class structure
- Remove automatic skipping of bundle install in playground apps
- Update ruby calendar test
- Update cypress calendar test
- Refactor calendar test environment to use activerecord
- Add code for calendar counts
- Remove redundant Warning
- Convert calendar.ru to calendar_rails.ru
Version 8.4.5
- Fix pluralization rule link on locale files (#716)
- Install gems in pagy CI
- Indentation changes
- Remove :cycle false default
- Fill aria_label.nav ca pluralized entry (#715) (Fixes #581)
- Fix typos (#710)
Version 8.4.4
- Update eslint: new configuration, stricter rules and javascript code
Version 8.4.3
- Deprecate/rename javascript files keeping copies of old files to avoid production breaking changes; updates playground apps
Version 8.4.2
- Limit the playground --rerun option to linux platforms
- Simplify and improve the js environment by using bun
Version 8.4.1
- Fix pagy.in in pagy_get_items method introduced in 8.4.0 (see #696) (closes #704) (closes #708) (#707)
- Fix renamed Frontend Helpers to JS Tools and typo
next_a"aria-label" (#700) - Fix rubocop
Version 8.4.0
- Retrieve only @in items:
- improve the performance of the last page in
particular storage conditions (see #696)
- improve the performance of the last page in
- Improve pagy launcher for pagy devs
Version 8.3.0
- Discontinue foundation materialize, semantic and uikit CSS extras
- Improve playground:
- Add install option (automated in pagy development)
- Fix HTML validation for all apps
- Remove unused styles from the demo app
- Hardcode version in pagy.gemspec
Version 8.2.2
- Add nav translation for ko (closes #592) (#690)
Version 8.2.1
- Fix empty page param raising error (closes #689)
Version 8.2.0
- Fix the '#pagy_url_for' method for calendar pagination (#688)
- Extend the use of pagy_get_page to the arel, array and countless extras
- Add the pagy_get_count method to the backend
Version 8.1.2
- Added "da" locale for aria_label.nav (closes #583)
Version 8.1.1
- Fixed broken aria-label for disabled links in Foundation (#685)
- Simplification of input variables and defaults: params and request_path are not instance variables
Version 8.1.0
- Implement max_pages to limit the pagination regardless the actual count
- Improve efficiency of params in pagy_url_for
- Remove nil variables from DEFAULT
- Removed redundant @pages, aliased with @last
Version 8.0.2
- Minor change in rails app and RM run config
- Fix canonical gem root:
- Correct script.build: "NODE_PATH="$(bundle show 'pagy')/javascripts"
- Move pagy.gemspec inside the gem root dir
- Fix for Turbo not intercepting changes in window.location
- Use require_relative for gem/lib files
- Complete translation of aria.nav for "ru" locale (close #599)
- Docs improvement and fixes
Version 8.0.1
- Reorganize the gem root dir: it was the lib dir (containing everything), now is the gem dir (containing lib and everything
else). - Fix broken link in README
Version 8.0.0
Breaking changes
- Renamed/removed the following arguments for all the helpers:
- Search
pagy_id:, replace withid: - Search
nav_aria_label:, replace witharia_label: - The
nav_i18n_keyhas been removed: pass the interpolated/pluralized value as thearia_label:argument - The
item_i18n_keyhas been removed: pass the interpolated/pluralized value as theitem_name:argument - The
link_extra:has been removed: its cumulative mechanism was confusing and error prone. The:anchor_stringpagy
variable substitutes it, however it's not an helper argument anymore, so you can assign it as theDEFAULT[:anchor_string]
and/or pass it as any other pagy variable at object construction. (
See customize the link attributes)
- Search
- HTML structure, classes and internal methods have been changed: they may break your views if you used custom stylesheets,
templates or helper overrides. See the complete changes below if you notice any cosmetic changes or get some exception. - The
navsandsupportextras has been merged into the new pagy extra.
Search for"extras/navs"and"extras/support"and replace with"extras/pagy"(remove the duplicate if you used both) - The
"extras/frontend_helpers"has been renamed to"extras/js_tools" - The build path for javascript builders has been updated to the canonical paths for gems, and has moved from the
libto
the gem root. Notice that the correct setup inpackage jsonwas still wrongly wrapped in thegemdir for 8.0.0-8.0.1, and it
has finally been fixed in 8.0.2 (sorry for that):- 8.0.0-8.0.1 only:
build: "NODE_PATH=\"$(bundle show 'pagy')/gem/javascripts\" <your original command>" - 8.0.2+:
build: "NODE_PATH=\"$(bundle show 'pagy')/javascripts\" <your original command>"
- 8.0.0-8.0.1 only:
Changes
- Streamlined HTML and CSS helper structure. You may want to look at the actual output by running
the pagy demo- The
pagy_navandpagy_nav_jshelpers output a series ofatags inside a wrappernavtag (nothing else) - The disabled links are so because they are missing the
hrefattributes. (They also have therole="link"
andaria-disabled="true"attributes) - The
currentandgapclasses are assigned to the specificatags - HTML changes
- All the pagy helper root classes have been changed according to the following rule. For example:
"pagy-nav">"pagy nav""pagy-bootstrap-nav-js">"pagy-bootstrap series-nav-js"- and so on for all the helpers
- The
activeclass of the*nav/*nav_jslinks as been renamed ascurrent - The
disabled,prev,nextandpagy-combo-inputlink classes have been removed (see
the stylesheets for details) - The
rel="prev"andrel="next"attributes have been dropped (they are obsolete) - The
<label>/</label>and**/**wrappers in the dictionary files have been removed
- All the pagy helper root classes have been changed according to the following rule. For example:
- The
- The
pagy_link_procmethod (only used internally or in your custom overriding) has been renamed topagy_anchorand it works
slightly differently:- The
link_extra:key argument has been removed- The
extrapositional argument of the returned lambda has been removed - The
classes:andaria_label:keyword arguments have been added to the returned lambda
- The
- The
- The
nav_aria_label_attrmethod has been renamed asnav_aria_label - The internal
prev_aria_label_attrandnext_aria_label_attrmethods have been removed - The
gapin the nav bars is a disabled anchor element (atag without ahrefattribute) - The
pagy_prev_htmlandpagy_next_htmlhave been renamed aspagy_prev_aandpagy_next_a - The
pagy_prev_link_tagandpagy_next_link_taghave been renamed aspagy_prev_linkandpagy_next_link - The
*combo_nav_jsandpagy_items_selector_jshelpers use a more efficient code - The
src/pagy.tsand relative built javascript files have been adapted to the above changes - The stylesheets are a lot simpler as a consequence of the changes above
- All the
*combo-nav_jsof the framework extras use simpler structure and improve the look and feel consistently with their
respective frameworks - All the frontend extra have been normalized and are totally consistent with each other; a few may add the
classes:
argument to a few components, when the framework allows it. - Created the pagy playground system of apps working with the
pagyexecutable. - Internal renaming
FrontendHelpers>JSTools - Fix broken link of pagy.rb in docs (closes #668, #669)
- Docs Improvements
- Better code issue template
Version 7.0.11
- Fix jsonapi prev and next keys for unavailable links (#665)
- Docs fixes
Version 7.0.10
- Added name attribute to combo and items input tags; removed pagy_marked_link and refactored js input action
Version 7.0.9
- Improve all pagy apps
- Normalized bootstrap, bulma, foundation, navs extra
Version 7.0.8
- Update gems and fix a rubocop bug
- Add all styles to pagy_styles.ru
- Better pagy stylesheets
- Fix for uikit extra prev and next link duplicating chevrons
- Change aria_Label to aria_label for Arabic locale (#657)
Version 7.0.7
- Fix for retype excluding linked files and showing category images
- Fix for first *nav_js page not active with trim (introduced with the #656 fix 7e2f118)
- Normalize pagy apps; implement pagy_styles.ru
Version 7.0.6
- Internal renaming of frontend constants
- Fix for disabled links and missing or extra ARIA attributes in frontend extras
- Bootstrap fix for current page link; pagy.js fix for trim of current page (closes #656)
Version 7.0.5
- Updated gems, npm modules, contributors
- Added the pagy stylesheets to the gem, updated apps, docs and manifest
- Added note for the metrics and compacted the chart section (closes #652)
- Docs: fix formatting, grammar in README.md (#654)
- Add note about PR base branches to readme (#653)
Version 7.0.4
- Tailwind styles integrated with the pagy-items-selector-js (#646)
- Deprecated the "pagination" CSS class, use the "pagy" CSS class that has been added to all the interactive pagy helper outputs
- Fix indentation of cs locale (#648); add "pagy.aria_label.nav.few" entry, duplicating the "other" pluralization
- Update cs translations (#648)
- Expand/Correct changes about
pagy.prevandpagy.next(#649)
Version 7.0.3
- Remove extra space in
pagy_nav,pagy_nav_jsand.pagy-combo-input - Refactor of tailwind styles and docs (closes #646)
- Add
pagy_tailwind_app.ru(#646) - Add missing CSS breaking change to the CHANGELOG (#646)
Version 7.0.2
- Fix for missing to fetch count_args default (close #645)
- Non-code improvements
Version 7.0.1
- Updates ckb translations to be complaint with ARIA in v7.x.x (#643)
Version 7.0.0
Breaking changes
- Dropped old rubies support: Pagy follows the ruby end-of-life supported rubies now.
- Renamed
:i18n_key>:item_i18n_key - Refactored
supportextra- Renamed
pagy_prev_linktopagy_prev_htmlto avoid confusion with pagy_prev_link_tag - Removed
pagy_next_linktopagy_next_htmlto avoid confusion with pagy_next_link_tag
- Renamed
- Rack 3 breaking changes:
- The
headersextra produces all lowercase headers, regardless how you set
them see rack issue - Removed
:escaped_htmloption frompagy_url_for(only breaking if you override the method or use the option directly)
- The
- Dictionary structure changes: (affects only app with custom helper/templates/dictionary entries)
- The
naventry has been flattened:pagy.nav.*entries are nowpagy.*:- If you have custom helpers/templates: search the keys that contain
'.nav.'and replace them with'.' - If you have custom dictionary entries (overrides): remove the
'nav:'line and unindent its block
- If you have custom helpers/templates: search the keys that contain
- A few labels used as
aria-labelhave been added: you may want to add/use them to your custom helper/templates/dictionaries
for ARIA compliance.pagy.aria_label.navPluralized entry: used in thenavelementpagy.aria_label.prev,pagy.aria_label.nextSingle entry: used in the prev/nextalink elements
- The
Default changes (possibly breaking test/views)
- Changed
Pagy::DEFAULT[:size]variable defaults from[1, 4, 4, 1]to7. You can explicitly set/restore it in the
initializer, if your app was relying on it. - Added sensible
:sizedefaults in Calendar Unit subclasses. You can explicitly set it in the initializer, if your app was
relying on it.Pagy::Calendar::Day::DEFAULT[:size]31Pagy::Calendar::Month::DEFAULT[:size]12Pagy::Calendar::Quarter::DEFAULT[:size]4Pagy::Calendar::Year::DEFAULT[:size]10
- Changed a few
formatdefaults in Calendar Unit subclasses. You can explicitly set it in the initializer, if your app was
relying on it.Pagy::Calendar::Day::DEFAULT[:format]from'%Y-%m-%d'to'%d'Pagy::Calendar::Month::DEFAULT[:format]from'%Y-%m'to'%b'Pagy::Calendar::Quartr::DEFAULT[:format]from'%Y-Q%q'to'Q%q'
Visual changes (possibly breaking test/views)
- The ARIA label compliance required the refactoring of all the nav helpers that might look slightly different now:
- The text for
"Prev"and"Next"is now used for thearia-label(actually as"Previous"and"Next") and has been
replaced in the UI as<and>. You can edit the dictionary entriespagy.prevandpagy.nextif you want to revert it to
the previous default (‹ PrevandNext ›)
CSS changes (possibly looking different/broken)
- The HTML of the current page in
pagy_navandpagy_nav_jshas been changed from simple text (e.g.5) to a
disabled link (e.g.<a role="link" aria-disabled="true" aria-current="page">5</a>). That affects your CSS rules and
the old tailwind examples targeting the page links, now overreaching the current page.- You may fix eventual problems either by replacing the affected
arules with narrowera[href]selectors however if you use
Tailwind we recommend to use the improved tailwind style, that you can
adapt in no time to anything you need.
- You may fix eventual problems either by replacing the affected
- The extra spaces added between pages of
pagy_navandpagy_nav_jshave been removed - The
pagy-combo-nav-js .pagy-combo-inputinternal element x-margins have been removed
Internal renaming of private methods (unlikely to break anything)
You should not have used any of the private methods, but if you did so, you will get a NoMethodError
(undefined method...) very easy to fix by simply renaming, because there are no changes in the logic.
Changes
- Added
:count_argsvariable passed to thecollection.count(...)statement (avoids overriding ofpagy-gets-varsand
expands count capabilities) - ARIA compliance
- Removed the pagy templates: they were a burden for maintenance with very limited usage,
still you can use them - Added a simpler and faster nav without gaps (just pass an integer to the
:size) - Internal renaming of private frontend methods
- Updated code and tests for latest gem and npm module versions
- Internal improvements of automation scripts
Version 6.5.0
- Add ckb: "pagination" entry (#641)
Version 6.4.4
- Adapt pagy-ci workflow to run on current gemfile (no-failure for new gems enabled in leading version)
- Fix for wrong arguments types in meilisearch pagy_search extension
Version 6.4.3
- Exclude coverage for prepend conditional, ruby < 3.0 syntax for prepend
Version 6.4.2
- Better module overrides in jsonapi
- Replaced the is_a?(Hash) check for jsonapi reserved :page param with respond_to?(:Fetch) and prepended to the Frontend
- Docs improvements and fixes
Version 6.4.1
- Remove dependency on base64 (#618)Ruby 3.3 prints a warning if base64 is used without specifying it in the gemfile.
Ruby 3.4 will error
Version 6.4.0
- Implement JSON:API specifications
- Added simpler nav generation, triggered by setting the size variable to a positive Integer
- Fix for pagy_calendar_app.ru
Version 6.3.0
- Calendar improvements:
- Added the :fit_time option to page_at and pagy_calendar_url_at methods. It avoids the OutOfRangeError by returning the first or last page
- Added starting_time_for and page_offset_at feedback methods to the Calendar base class
- Prepended the pagy_calendar_url_at to the Frontend and Backend
- Added calendar showtime
- Updated node modules (dev on node 20)
- Updated Gemfile and fixed new rubocop complaints
Version 6.2.0
- Add Belarusian locale (#567)
- Reordered RubyMine tasks (fix #541)
Version 6.1.0
- Add Vietnamese locale (#550)
- Maintenance (docs, test, gems and node modules updates) fixes and improvements
Version 6.0.4
- Updated gems and npm modules
- fix: Extras::Trim - fix trimming first page (#516)
- Fix for new rubocop
Version 6.0.3
- Updated Gemfile and npm modules
- Improved Danish translation (#502)
Version 6.0.2
- Fix: foundation combo helper (#469)
Version 6.0.1
- Fix for pagy_bootstrap_combo_nav_js disabled input in certain bootstrap versions
- Fix for wrong module in standalone extra
- Fix for broken links in code comments and docs
Version 6.0.0
Breaking changes
Removed support for the deprecation of 5.0:
- The
pagy_massage_paramsmethod: use the:paramsvariable set to a lambdaProcthat does the same (but per instance). See How to customize the params. - The
activesupportcore dependency is now an optional requirement if you use the calendar: you must addgem 'activesuport'to your Gemfile if your app doesn't use rails. - The plain
Timeobjects in the:periodvariable: use onlyActiveSupport::TimeWithZoneobjects. - The
:offsetvariable used by thePagy::Calendar::Week: set theDate.beginning_of_weekvariable to the symbol of the first day of the week (e.g.Date.beginning_of_week = :sunday). Notice the default is:mondayconsistently with the ISO-8601 standard (and Rails). - The
Pagy::DEFAULT[:elasticsearch_rails_search_method]: usePagy::DEFAULT[:elasticsearch_rails_pagy_search]instead. - The
Pagy::DEFAULT[:searchkick_search_method]: usePagy::DEFAULT[:searchkick_pagy_search] instead. - The
Pagy::DEFAULT[:meilisearch_search_method]: usePagy::DEFAULT[:meilisearch_pagy_search]instead.
Suggestions for a smooth removal of deprecations from pagy 5
- Upgrade to the latest version of pagy 5 (5.10.1)
- Run your tests or app
- Check the log for any deprecations message starting with '[PAGY WARNING]'
- Update your code as indicated by the messages
- Ensure that the log is now free from warnings
- If you are overriding the
pagy_url_formethod ensure you add the extra parameters required.. - Upgrade to pagy 6
Changes
- Added new doc changes
- Replaced the gitter support with the Q&A discussion links
- reorganized cypress tests
- Updated run configurations
- Fix for bump.sh
- Add Meilisearch finite pagination by default in the meilisearch extra (#417)
- Allowing users to override the request path (#404)(squashed)
- Fix the args in the Pagy::Countless#series override (#411)(fixes #410)
- update: pagy_bare_rails script: for db testing (#379)
- Fix rubocop glitch
- added specific typescript installation to pagy-ci
- Chore: update github action versions to latest
- Reorganized pnpm setup and updated pagy.js to the new parcel default
- Reduced the error level for eslint rules
- Add Dependabot for GitHub Actions (#392)
- Fix NoMethodError when page param is hash (#390)
- Removed deprecated variables for the search extras
- Removed deprecated :offset variable for Calendar::Week
- Removed deprecated support for Time instances
- Removed activesupport hard dependency
- Removed support for deprecated pagy_massage_params
- fixup .gitignore
- Dropped docker env support
- Calendar code cleanup and normalization
- Implementation of calendar extra feature: pagy_calendar_url_at; refactoring and testing of the calendars files
- Pagy::Calendar::*: Simpler code and improved readability
- Added Pagy::Calendar#page_for(time) helper
- Fix for ignored pnpm files from other branch
- Updated cypress action
- Updated node modules and cypress 12
- Updated gems and rubocop config
- Remove aria-label="pager" (#412)
- Update korean translation (#413)
- Fixed small typo in German (#409)
- fix: Added Norwegian Nynorsk translation (#408)* Added Norwegian Nynorsk translation
- Fix Pagy configuration and documentation for renamed "pagy/extras/shared" to "pagy/extras/frontend_helpers" (#399)
- update link: to referenced rails apps (#384)
- Added reference to avoid N+1 queries when using
includes(closes #378) - Fix for broken links in docs
- Added note about overriding the
pagy_headersmethod in theheadersextra - Bundle and npm updates
- Add: documentation changes (#376)
- Added post link in README; fix for another example in how-to.md
- Fix for example in how-to.md (closes #373)
- Added missing info
- Fix: docs - typo, minimise ambiguity (#372)
Version 5.10.1
- Changed default for :meilisearch_search method to always defined :ms_search method
Version 5.10.0
- Adjusted Psych::VERSION condition to avoid deprecations
- Improvement of search extras: (closes #367) (closes #369)
- Added DEFAULT[:*_search] variables used to call the original :search method
- Deprecated and renamed DEFAULT[:_search_method] to DEFAULT[:_pagy_search]
- Updated config, docs and CHANGELOG deprecations
- Fix for wrong calculation of :page in Pagy.new_from_meilisearch (closes #368)
- Faster assignment of javascript path
- Simplified webpack config, added rollup config and normalized doc
- Better javascript doc (closes #365)
- Added specific webpack javascript configuration info; a few minor doc adjustments
- Added specific webpack javascript configuration info
- Update javascript.md (#362)
Version 5.9.3
- Fix for too generalized html_escape in pagy_url_for. (closes #363)
- Docs updates
Version 5.9.2
- Added info about using pagy-module.js with importmap
- Bundle and npm update
- Fix for non escaped query strings in links
- Small improvements in src files
- Added legacy methods to use the javascript files
- Added missing require in docs
- Updated docs with the proper way to use pagy with esbuild
- Docs improvements
- Improved the javascript files docs and moved into the lib/javascripts/README.md file
Version 5.9.1
- Updated build.sh to set window.Pagy in pagy-dev.js
- Update pagy.md (#360)
- Minor - fix syntax highlighting (#361)
- Updated info about the current way to use pagy.js with jsbuilder-rails/esbundle
Version 5.9.0
- Npm and bundle update
- Fix and refactoring of pagy calendar calculation of local time (closes #358):
- The
Pagy::Calendar::*classes require ActiveSupport (temporarily added activesupport dependency that will e replaced in 6.0) - The
:perioditems can beTimeorTimeWithZoneobjects (which work across DST ranges) - Deprecated use of
:offsetto set the first weekday, in favour ofDate.beginning_of_week(default to:monday) - Added DST specific tests
- Fix for calculation of label quarter
- Updated docs and tests
- The
- Fix for wrong offset in gearbox extra (closes #356)
- Reduced the public interface of pagy.js and relative files to just
versionandinit() - Add Ruby 3.1 to CI (#354)
Version 5.8.1
- Shorter warning messages and minified pagy.js
- Fix for wrong decoding of non latin charsets
Version 5.8.0
- The JSON in data-pagy attributes is base64 encoded: it is smaller than HTML escaped and it avoids crawlers to follow look-alike links
- Removed redundant PagyJSON type
Version 5.7.6
- Updated Gemfile.lock and package-lock.json
- Broader browserslist and better doc for javascript
- Updated build.sh
- Improvement of pagy.ts:
- Moved warn() out of init()
- More inclusive try block
- Simplified rjsObserver function
- Replaced getOwnPropertyNames with keys
- Fix for missing entry in CHANGELOG.md
Version 5.7.5
- Fix for unwanted offset in source map data
Version 5.7.4
- Added parcel-plugin-nuke-dist
- Renamed pagy.mjs -> pagy-module.js; added TypeScript declaration file and build.sh
Version 5.7.3
- npm update
- Simper pagy-dev.js; added pagy.mjs module
- Updated .eslintrc.json and package.json files
Version 5.7.2
- Simplified keyword naming
- Better compilation and development support for pagy.js. Replaced babel with parcel.
Version 5.7.1
- Simpler syntax for nav js helpers
- Added input e2e test file
- Simpler abstraction of input based js helpers
Version 5.7.0
- Bundle and npm update
- TypeScript/Javascript improvements:
- More efficient handling of responsive *nav_js helpers
- Replaced window resize event listener with ResizeObserver
- More robust input based js helpers (catching possible invalid user input)
- Improved typing, function naming
- Added error catching
Version 5.6.10
- Improvement and fixes for client-side related structure
- Replaced e2e/cy script with a couple of npm scripts backed by the start-server-and-test
- Added trim test for items_selector_js; cleanup of e2e dir
- Normalized json files indentation
- Added trim to e2e tests
- Reorganized cypress tests: faster and more accurate
- Simpler pagy.ts
Version 5.6.9
- Better doc for e2e related commands in docker/README.md
- Updated package-lock.json and improved ci-cache.sh
- Used better syntax and code style in typescript files
- Updated copyright year
- Refactoring of typescript related files and dirs:
- Moved e2e dir in the project root
- Added typescript linting plugins and configuration
- Converted all the e2e test to typescript
- Updated Docker, VSC and .idea configurations
Version 5.6.8
- Reorganized TypeScript/JavaScript with npm workspaces and better script naming
- Fix typo in gemspec
- Better typescript configuration with source maps and declarations
Version 5.6.7
- GitHub Actions: added quotes to version ruby 3.0
- Added typescript + babel environment for better pagy.js
- Updated e2e environment
- Updated gemfiles
- Fix for support doc snippets and other typos
- Minor update of gemfiles and docs
- Added more gemspec metadata entries (closes #351)
Version 5.6.6
- Docs improvements
- Added **_ to series and sequels
- Updated rematch and gemfiles
- Updated release-gem.yml workflow
Version 5.6.5
- Improved a few code comments; added post link in README
- Full name for translate, aliased as t
- Added check for no calendar units in pagy_calendar configuration
- Updated gemfiles
- Small docs layout adjustment
Version 5.6.4
- Updated RM run configurations
- Fix for missing innerHTML reset, unintentionally committed during a cleanup (closes #350)
- Updated gemfiles, docs and comments
Version 5.6.3
- Improved readability and efficiency of calendar files
- Fix for English spelling in local variable name
Version 5.6.2
- Updated pagy.manifest for Tamil locale
- Add Tamil (ta) translation (#349)
- Internal changes in calendar files:
- Simpler calculations for month mixin
- Normalized naming of non-api methods
- Better comments
- Pagy::I18n: small performance improvement
- Docs reorganization
- Update paths_ignore for skip CI and docs
Version 5.6.1
- Updated cypress and bundler
- Improved efficiency of unit labelling and support for custom calendar unit sub formats
- Added missing initializer default for calendar quarter and missing doc for custom units
Version 5.6.0
- Updated gemfiles
- Updated docs
- Added calendar quarter tests
- Internal calendar refactoring to allow custom units; added quarter unit
Version 5.5.1
- Docs updates
- upgrade bootstrap template navs: call pagy_link_proc with link_extra key (#348)
- Renamed internal #time_for -> #start_for
- Docs fixes and improvements
Version 5.5.0
- Updated cypress and related packages
- Calendar API: FINAL breaking changes (stable from now on):
- Refactoring of calendar classes and variables:
- Moved calendar defaults from
Pagy::DEFAULTto class-specificPagy::Calendar::*::DEFAULT - Renamed variables:
:minmax->:period:time_order->:order:week_offset->:offset:*_format->:format
- Returning local time instead of UTC time for the utc accessors, now renamed:
#utc_from->#from(usefrom.utcif you need it)#utc_to->#to(useto.utcif you need it)
- Inverted the logic for the
:skipkey in the#pagy_calendarconf, now renamed::skip->:active
- Renamed methods:
#pagy_calendar_minmax->#pagy_calendar_period#pagy_calendar_filtered->#pagy_calendar_filter
- Added alternative way to delegate the localization to i18n without the i18n extra
- Updated
pagy_calendar_app.ru - Fix for wrong reordering in
:descorder - Documentation fixes and improvements
- Removed the warning for the API changes: the API is stable after these changes
Version 5.4.0
- Calendar API breaking changes for refactoring of
Pagy::Calendarand calendar extra:- Added complete compatibility with all the backend extras
- Simpler usage with automatic handling of pagy objects
- Less variables and simpler requirements for the methods to implement
- Updated gemfiles
- The localize method overridden by the i18n extra must receive a format
- Series and sequels use keyword arguments and pagy_*nav methods accepts a size keyword argument
- Docs improvements
- Removed unnecessary empty section in calendar docs
- Fixes for typos and misalignment
Version 5.3.1
- Added screenshot to the calendar extra (closes #346)
- Added bump.sh script to bump the version in multiple files; check for consistency and optionally commit the changes
- Minor fixes
- Changelog improvements
- Reversed CHANGELOG (closes #345)
- Calendar I18n small internal renaming and docs improvements
Version 5.3.0
- Implemented localization of time labels through the i18n extra delegation
- Renamed internal module and files of SharedExtra to FrontendHelpers
- Added support for
*nav_jsto Calendar - Simplified page labelling, moved into the pagy classes and removed frontend methods
- Deprecated
pagy_massage_params: use the :params variable set to a Proc that does the same, but per instance - Added apps README
- Completed overflow fix for pagy Countless
Version 5.2.3
- Fix for overflow :empty_page in regular Pagy instances, not returning an empty page
- docs: add tutorial, simplify header (#343)
- Refactoring of rails_inline_input.rb (include and close #342)
Version 5.2.2
- Fix for missing defined?(Calendar) checks; small simplification in headers extra
- Calendar docs improvements and fixes
Version 5.2.1
- Reorganization of mock collection classes; enabled rubocop layout in tests
- Small refactoring of the overview extra
- A few improvements for the Calendar pagination; added the current_page_label method
Version 5.2.0
- Small changes in code; updated gemfiles, tests and docs
- Implemented calendar extra to paginate a Time periods by unit (year, month, week or day)
- Added pagy_labeler frontend method overridable for changing the link text from a simple page number to any arbitrary string
- Enabled rubocop Style/Documentation cop
- Updated npm modules and gemfiles
- Docker better mounts
- Used gem-generic release-gem action
Version 5.1.3
- Added single action standalone rails_inline_output.rb
- Small improvements in code and docs
- Fix for rails problem with internal params in pagy URL (closes #341)
- Documentation improvements
- A few details tag in the README should be opened by default
Version 5.1.2
- Refactoring of pagy_url_for and relative test:
- Fix for ignoring the items_extra variable
- Replaced request.GET with request.params to enable POST pagination
- Refactoring of Mock test classes for better handling of params
Version 5.1.1
- This reverts commit 1d77e672d5b7813108b40c13ca93fdec045f4c03.
Generating the URL by using the application params method breaks rails apps because it requires manual changes in the apps.
Version 5.1.0
- Fix and refactoring of pagy_url_for and relative test:
- Fix for ignoring the params not coming from the request
- Fix for ignoring the items_extra variable
- Refactoring of Mock test classes for better handling of params
- Improved code comments, formatting and docs fixes
- Countless extra: simplified code, internal renaming of locals and docs update
Version 5.0.1
- Updated docs and issue templates
- Added cypress-dark theme to e2e test
- Refactoring of coverage to include 100% of line and condition branches covered
- Simplification of metadata extra
- Refactoring of exceptions
- Added CHANGELOG_LEGACY
Version 5.0.0
Breaking changes - 1. Code update
Pagy 4 dropped the compatibility for old ruby versions >2.5 and started to refactor the code using more modern syntax and paradigms and better performance. It deprecated the legacy ones, printing deprecation warnings and upgrading instruction in the log, but still supporting its legacy API. Pagy 5.0.0 cleans up and removes all that transitional support code.
The changes for upgrading your app cannot be fixed with simple search and replace, but fear not! Fixing them should just take a few minutes with the following steps:
- Upgrade to the latest version of pagy 4
- Run your tests or app
- Check the log for any deprecations message starting with '[PAGY WARNING]'
- Update your code as indicated by the messages
- Ensure that the log is now free from warnings
- Upgrade to pagy 5
FYI: Here is the list of the deprecations that are not supported anymore:
Removed support for deprecated variables
Pagy::VARS[:anchor]is nowPagy::DEFAULT[:fragment]
Removed support for deprecated arguments order
- The argument order in
pagy_url_for(page, pagy)is now inverted:pagy_url_for(pagy, page)
Removed support for deprecated positional arguments
The following optional positional arguments are passed with keywords arguments in all the pagy helpers:
- The
idhtml attribute string with theidkeyword - The
url|absoluteflag with theabsolutekeyword - The
item_namestring with theitem_namekeyword - The
extra|link_extrastring with thelink_extrakeyword - The
textstring with thetextkeyword
Breaking changes - 2. Simple search and replace
There are a few renaming that have not been deprecated in previous versions because they are extremely easy to fix with simple search and replace (while implementing deprecations would have been detrimental to performance and complex for no reason)
Consistency renaming
A few elements have been renamed: you code may or may not contain them. Just search and replace the following strings:
- Rename
Pagy::VARStoPagy::DEFAULT - Rename
enable_items_extratoitems_extra - Rename
enable_trim_extratotrim_extra - Rename
Pagy::HelperstoPagy::UrlHelpers - Rename
pagy_get_paramstopagy_massage_params
Items accessor
The items accessor does not adjust for the actual items in the last page anymore. This should not affect normal usage, so you can ignore this change unless you build something on that assumption.
If your code is relying on the actual number of items in the page, then just replace @pagy.items with @pagy.in wherever you meant that.
FYI: The @pagy.items is now always equal to @pagy.vars[:items] (i.e. the requested items), while the @pagy.in returns the actual items in the page (which could be less than the items when the page is the last page)
Changes
- Removed support for deprecations
- Refactoring of Pagy and Pagy::Countless classes, I18n, and url helpers
- Refactoring of the docker environment, addition of ready to use VSCode setup
- Changed general module structure (use of prepend instead of re-opening modules)
- Added gearbox extra for geared pagination
- Added configuration files for a full working VSCode devcontainer environment
- Added Run Configurations for RubyMine
- Improved the usage of e2e tests
- Updated doc, gemfiles and github workflow
- Other minor fixes and improvements in code and doc
Version 4.11.0
Changes
- added countless_minimal feature
- added missing deprecation to countless class
- doc improvements
Commits
- 5103ee9: added countless_minimal feature
- ed6bc0b: added missing deprecation to countless class
- bedb2d6: Fix - link directly to docs [ci-skip] (#328)
- 74aa300: Remove minor extra parenthesis in trim docs [ci-skip] (#326)
- f8b96eb: docs - add links directly to docs page [ci-skip] (#324)
Version 4.10.2
Changes
- improve the customization of url when using the trim extra
- better tailwind rules
- doc fixes and improvements
Commits
- 9e7fd48: improve the customization of url when using the trim extra (closes #325)
- 0d48b5f: better handling of extra docker-compose run files
- f5ed8f6: added note about the possible workaround for bundler/inline bug
- 2715660: doc fixes
- 7187101: Javascript doc improvements
- 24b7e78: release workflow refactoring
- 20d1d8e: chore: add github action - publish & tag versions (#322)
- 922fd7f: better tailwind rules
- 28983e6: added doc for using Searchkick.pagy_search (closes #319)
Version 4.10.1
Changes
- fixes for meilisearch extra
Commits
- ec748c2: Fixes for Meilisearch extra (#318)
Version 4.10.0
Changes
- added arabic locale
Commits
- 9bc548e: added missing keys for Arabic (#317) (closes #295)
- 1b95674: Add arabic locale, pluralization and tests; alpha ordered tests
Version 4.9.0
Changes
- added meilisearch extra
- docs fixes
Commits
- 572ed78: updated pagy-ci.yml
- 8fe1d19: Fix documents for searchkick (#315)
- 744717f: Meilisearch extra (#316)
- fb65260: updated issue templates
- 1c3d283: Added Pagy::Console links to README
Version 4.8.1
Changes
- fix for deprecation and test improvements
Commits
- 0f1a7f2: improved deprecation_tests (see #311)
- 7e9c9cd: fix(pagy): deprecated_var is a class method (#311)
Version 4.8.0
Changes
- Lowered minimal ruby version requirement to 2.5+
- Simpler tests using the
rematchgem - Docker environment improvements
Commits
- b5b500a: Merge branch 'backport-to-2.5' into dev
- 001f22f: fix for different handling of module prepend in ruby <3
- d6d71a5: fix for frozen error handled differently on ruby <3
- 8a2cf76: replaced syntax not available in ruby 2.5
- 14b3a0c: lowered the minimum ruby version requirement to 2.5
- 8c76943: updated Gemfile.lock
- 934f602: added comment in doc example about the inverted order of arguments in previous versions
- acd59f5: moved command out of default docker-compose to its own file in order to avoid error before first bundle install
- 527a14f: Gemfile update
- 842de05: better tests and stricter rubocop
- d82e95c: Gemfile updated and used for CI
- 675f587: Gemfile: added gemspec and updated rematch
- b0a6603: Updated to rematch 1.0 and copyright year
- 8bda6a9: added rematch gem and reset rematch stores
- f62fa88: added e2e tests to ci
- 04755aa: updated puma
- 4ec03f1: added HTML validation for all the helpers and styles
- 87b2f62: refactoring e2e: replaced snapshot plugin; updated to cypress 7.3.0
Version 4.7.1
Changes
- Fixed a couple of HTML validity issues with uikit and materialize combo_nav_js
- Improved rematch testing
- Updated the documentation
Commits
- 8cb4193: fixed and simplified uikit combo nav
- f762aca: used chip class for materialized combo nav
- 064a2b5: rematched tests
- 2a45321: expanded the combo nav label to the whole text
- 37c65a8: fixed and simplified materialize combo nav
- 789773b: removed faulty PAGY_REMATCH variable function; added rematch_all rake task
- eb2df6d: updated docs [skip ci]
Version 4.7.0
Changes
- Refactoring of pagy-json tags into data attributes
- Added the rematch testing system to ease maintenance of tests
- Added Ukrainian locale
- updated Gemfile and doc
Commits
- 887c783: better doc for E2E testing
- 738fd93: updated manifest
- 0110e3a: Ukrainian locale (#310)
- 9265cd2: extended must_rematch to other tests
- d217965: refactoring of pagy_json_tag to pagy_json_attr: from script tag to data attribute
- 57e6f91: added rematch test to ease maintenance of tests
- 94561a0: updated puma
Version 4.6.0
Changes
- Added labels to all input tags for improved usability and compliance
- Fixed a few HTML typos and redundant or illegal attributes
- Improved Sinatra app usable for experiment with pagy and providing support for ode issues
- Documentation improvements
- Added E2E testing for all pagy helpers
- GitHub management improvements
Commits
- 0fe2e49: added helpers and navbar tests for all the styles; updated docker readme
- 26b57a8: Added fix for Cypress bug affecting the snapshots plugin, improved cypress dockerfiles; added cypress studio and basic try
- 7693b3e: cypress: updated images; better open-cypress.yml with persistent configuration settings; added snapshots plugin
- 94e262f: added label tag to the pagy inputs
- f5e3482: removed redundant role="navigation" attribute from nav tags; removed illegal aria-label="pager" from semantic div
- 0467d32: fixes for html typos in semantic, foundation and materialize helpers
- 3f2c9f0: doc small fixes
- bff8c5f: refactoring of sinatra apps; added quick-start doc section
- b0baaa5: simplified standalone_app.ru
- 5442b34: fix broken link [ci skip]
- 17b1faf: improved issue template [ci skip]
- f933cd7: Added issue template and standalone_app to use as a scaffold for reproducing issues [ci skip]
- c8e41e3: added superails screencast; resized thumbnails [skip ci]
- 6116c32: added a few references in the how_to doc [skip ci]
Version 4.5.1
Changes
- Better Pagy::Console usability
Commits
- 4ee8bbf: pagy console extracted in its own module
Version 4.5.0
Changes
- Added E2E infrastructure for development and testing
- Refactoring of Javascript and docker environment
Commits
- 1b7b014: Add: clarity, further instructions to run pagy tests [skip ci] (#304)
- 7c723ba: added basic structure to run cypress tests and open the cypress IDE
Version 4.4.0
Changes
- Passing positional arguments (besides
@pagy) to all the helpers is deprecated and it will be supported only until pagy 5.0 - All the helpers accept more optional keyword arguments variables, for example:
pagy*_nav(@pagy, id: 'my-id', link-extra: '...')pagy*_nav_js(@pagy, id: 'my-id', link-extra: '...', steps: {...})pagy*_combo_nav_js(@pagy, id: 'my-id', link-extra: '...')pagy_items_selector_js(pagy, id: 'my-id', item_name: '...', i18n_key: '...', link_extra: '...')pagy_info(@pagy, id: 'my-id', item_name: '...', i18n_key: '...')pagy_prev_link(@pagy, text: '...', link_extra: '...')pagy_next_link(@pagy, text: '...', link_extra: '...')pagy_link_proc(@pagy, link_extra: '...')pagy_url_for(pagy, page, absolute: nil)(notice the inverted page/pagy order with the legacypagy_url_for(page, pagy, url=nil))
- deprecated
:anchorvariable in favor of:fragment - Refactoring of rake tasks, tests, items extra, javascript helpers
- Gems and documentation updates and fixes
- Added standalone extra
Commits
- b69a2f2: Merge branch 'dev'
- 9611eac: updated CHANGELOG
- d977767: better links in extras.md
- aa83126: added standalone extra
- e22c9c3: Merge branch 'args-refactoring' into dev
- d791a04: deprecated :anchor variable in favor of :fragment
- e91e4da: [skip ci] update javascript documentation (#305)
- 034afe8: config/pagy.rb: moved pagy variables block at the beginning
- bd0bb6c: renamed :trim variable to the more explicit :enable_trim_extra; removed redundant tests
- 76096e7: simplified the items extra, and added its features to the array and arel extras
- 86fb20e: fixed pagy_semantic_nav hellips
- 2382482: added link_extra keyword arg to pagy_items_selector_js
- 627a0dc: also pagy_link_proc uses keyword arguments
- 8ff2665: completed args conversion also for pagy_url_for and pagy_metadata
- 6a8fbb4: added "pagy-info" and "pagy-items-selector-js" classes to helpers output
- ad350e1: pagy_info wrapped into span tag, and added id keyword arg
- 2faca63: small improvement to pagy_url_for
- 2acbac6: added "pagy-njs" class to all pagy*_nav_js helpers
- 670f5a5: updated documentation
- 64347f8: changed the argument order from pagy_url_for(page, pagy) > pagy_url_for(pagy, page) for consistency with all the other helpers; deprecation warning and support for pagy < 5
- 393d216: updated gems
- d2891fb: refactoring and additions of tests
- 1538f24: updated tests with keyword arguments
- 6ce0c1d: helpers: deprecated positional id argument and added keyword arguments
- 9fd7930: removed id method and added id arg to the pagy*_nav helpers
- ec74e4f: removed the mandatory id arg passed to pagy_json_tag; updated tests; simplified pagy.js using previousSibling
- 3f13014: added resource post and relative link [skip ci]
- 7927f37: added manifest:check to CI for master and dev and to the default rake task
- 01f8f1c: refactoring of Rakefile now split in different task files
Version 4.3.0
Changes
- Improved efficiency of #series algorithm
- Added new features to the trim extra
- Added rubocop compliance (additional rubocop-packaging plugin)
- Many test tasks improvements
- CI transition from Travis to Github Action
Commits
- 80cef45: updated Gemfile
- 3cc464b: added coverage_summary at the end of the default task; added possibility of creating a coverage report
- 0424b71: docs and comment additions/fixes [skip ci]
- b6115e7: Added explicit pagy.manifest to comply with rubocop-packaging (see also #297)
- ef1980e: refactoring of CI from Travis to Github Actions
- 9fb1195: more verbose condition
- fe565eb: removed RUN_RUBOCOP
- 60be542: fix missing codecov formatter/circular reference problem
- 8c4ccfc: rubocop: added rubocop-packaging plugin; expanded inclusion of files
- 487eb70: small code normalization
- 3ea2d27: codecov gets already required in travis on ruby 3.0 (but not locally)
- e17d294: improved series algorithm efficiency (now up to ~5x faster and ~2.3x lighter than the previous one)
- 1051e6d: trim feature: added :trim variable to opt-out to trim even with the trim extra loaded, or invert the logic to out-in by setting Pagy::VARS[:trim] to false
- ece4daa: minor code restyling
- 0e3a09d: added :ide_development bundle group; small README changes
- 5e6f749: simpler test tasks
- e5ee4e7: CI: Remove Bundler 1.x workaround (#296)The "github" source now has that form, already.
Version 4.2.0
Changes
- Fix for
Pagy::Frontend::I18nconflicting with rtheI18ngem namespace after inclusion and safer renaming of other modules - Fix the simplecov setup reporting less coverage than what's actually covered
- Updated Tailwind styles
- Included the test dir in the coverage check, refactoring and additions of tests
- Big code restyling following ruby 3.0 syntax and cops; tried to make the code simpler, more readable and verbose with almost negligible performance loss.
Commits
- a62ae94: Updated README
- 9efb908: removed ENABLE_OJ from tests and travis config
- dede255: removed RUN_SIMPLECOV option
- fc614bd: fix/refactoring for simplecov setup reporting less coverage than what's actually covered
- 5e6ecf1: refactoring of Rakefile
- aea25a1: code-restyling: test
- cb67353: code-restyling: extras
- b2dc35a: code-restyling: locales, config
- b638764: code-restyling: root files and Pagy Core
- aac54aa: Renaming prepended modules with more specific and safe naming convention (see Issue #290 PR #293)
- 3eef450: Simpler test for I18n namespace conflict
- b2aaa01: README: fix typo (#289) [ci-skip]
- 3a9e70f: Fix extra i18n namespacing (#293)* Add a test that looks at i18n working in Modules included (fixes #290)
- 8cd25d2: renamed docker > pagy-on-docker
- a8060b1: fixed doc typos
- f0e0d41: removed require for minitest/reporters
- c178c6f: docker README fixes [ci-skip]
- ac988fd: docs fixes
- 4d20d34: Update Tailwind styles (#285)
- 9a14400: Small README addition [ci-skip]
- 9b40cdd: Update frontend.md (#284) [ci-skip]
- 2bbf204: added Mike Rogers' screencast [ci-skip]
- b24b86d: Added note for brakeman false positive warnings (closes #243) [ci-skip]
- df3c8d6: small syntax normalization
- 618d226: docker README fix [ci-skip]
Version 4.1.0
Changes
- added Bosnian, Croatian and Serbian locales
Commits
Version 4.0.0
Breaking Changes
- renamed
Pagy::SearchasPagy::SearchkickorPagy::ElasticsearchRails
Changes
- Dropped support for all jruby versions and ruby version <3.0 (use pagy 3.x instead)
- Dropped deprecation for old/renamed locales
- Fixed error in searchkick extra with ruby 3
- Various refactorings taking advantage of the dropped support for old ruby versions
Commits
- 4d48d33: refactoring of pagy_json_tag
- 745e68f: minor fixes for docker
- 296f060: added pagy_search name customization to elasticsearch extras
- 98a5254: refactoring of the elasticsearch_rails extra matching the actual params of the search method
- 6966fe3: refactoring of elasticsearch extras
- aecb565: normalization of i18n naming
- b3f78b8: refactoring of items extra using module prepend instead alias method chaining and module_eval; refactoring of tests (countless was masking failures of elasticsearch extras)
- 8ec7893: refactoring of trim extra using module prepend instead alias method chaining
- 05d9e92: used ruby 3.0 syntax
- f1d89a5: refactoring of I18n extra using module prepend instead alias method chaining
- df8607e: refactoring of overflow extra using module prepend instead alias method chaining
- c361293: Gemfile: uncommented performance group
- 66e29d1: fixes for the docker README
- 2a343ce: added README note about versions
- dadd2f1: ruby 3.0 syntax
- ce1d7ec: removed legacy I18n compatibility
- 6751412: added a few env variables in order to control the verbosity of tests; added test for negative page number
- 3eac56b: removed unused Hash additional methods
- 24ab5c6: simpler travis setup
- ba100dc: updated documentation
- 5d53043: emptied CHANGELOG and dropped LEGACY_CHANGELOG
- 33c467a: removed MARK constant
- 49040fb: removed EMPTY constant used for legacy compatibility with frozen_string_literal
- b826f61: updated rubocop and fixed offending lines
- f075337: removed deprecated locales
- a70881a: updated version to 4.0.0
- 4676788: updated docker environment for pagy 4
- 4a85efe: updated gemfile and gemspec for pagy 4
- fcaab88: updated gemfile and gemspec
- 467b985: added docker development environment
Version 3.11.0
Changes
- added Swahili localization
Commits
- fbc322f: Add Swahili (sw) to pagy (#276)
- ebbac6b: Fix: broken links (#272) [ci-skip]
- 2178436: restored file removed by mistake
Version 3.10.0
Changes
- added Czeck localization
Commits
- 316183f: minor adjustments to p11n.rb; removed local file
- 2e7fa1b: Update with 'cs' (#269)added lambda for 'west_slavic' and 'hash for 'cs' language
- 70760c6: Czech localization (#268)
Version 3.9.0
Changes
- added link tags helpers to support extra
Commits
- a66491b: added link tags helpers to support extra
- 2ef08a9: @pagy_locale explicitly initialized to avoid warning
- 261c6a1: reorganized gemfiles for travis, removed jruby 9.2 tests and added CAVEATS and removed redundant ||=nil
- 619d7d1: updated gems
- fc861d8: added .gitattributes to fix github linguist [ci-skip]
- 287b94f: added Raul Palacio screencast link to README
- 52c65a3: added "Contributions" section in the README
- f09a80a: Add tutorial link to readme (#259)
- 86bf3dc: Fix: typo [ci-skip] (#257)
- bd3bcc7: Update copyright notice to 2020 (#256) [ci-skip]
- 01e4a14: [ci-skip] Add note re: html safe helpers (#254)Fixes discussion noted in: #6
- 1d812be: doc improvements [ci-skip]
Version 3.8.3
Changes
- Portuguese translation
- Fixes and documentation improvements
Commits
- f64a1d6: added pagy reference to jetbrains link
- 8a4596f: Add translation for Portuguese (#250) [ci-skip]
- 515de9b: Adds parentheses (#249) [ci-skip]
- 734f30c: added basic sinatra app
- c7aa44d: updated gems
- 62bd4ac: added tailwind extra styles
- c2e8eef: added "Customizing CSS styles" how to section
- 614a3e1: fix for extra "-js" in "pagy-combo-nav-js"
- 8673ca4: a couple of how_to additions
Version 3.8.2
Changes
- Fixes, improvements and gems updates
Commits
- a1a7962: gems update
- 0a70110: item_name can be overridden by passing an already pluralized string to pagy_info
- 28913d6: Use proper attributes for "previous" links (#244)
Version 3.8.1
Changes
- Various fixes ad gems update
Commits
- 1aa1fa7: gems update
- 289d38a: added conditional definition of pagy_t_with_i18n to avoid ruby 2.7 "last argument as keyword parameters" deprecation warning (closes #241)
- d571719: added raw_response method check for pagy_elasticsearch_rails (#234)
- 7a09bb9: fix typo in documentation
- d7a9f7a: Fixes boundary character escaping in regex in js trim function (#239)
- 3561885: gems update
Version 3.8.0
Changes
- Khmer translation
- Added support for elasticsearch < 6
- Documentation fixes
Commits
- bba1bca: used ternary conditional
- a9cee7d: Support ES5 on elasticsearch rails (#234)
- d58a39d: Khmer translation for pagy (#235)
- 7ced96c: fix for missing suffix fr method reference in doc
- 73600be: improved consistency in searchkick and elasticsearch_rails documentation examples (#231)
Version 3.7.5
Changes
- Danish translation
- Re-enabled legacy jruby travis config
- Added ruby 2.7 travis testing and rubocop config
Commits
- 721d01f: more documentation fixes and improvements
- 246fca7: Danish translation for Pagy (#232)
- e57215f: added ruby 2.7 travis testing and rubocop target version
- 280164a: re-enabled travis testing for old jruby (travis fixed the jruby images issue)
Version 3.7.4
Changes
- Locales normalization and deprecations
- Bundle update
Commits
- c424466: Merge branch 'locales-normalization' into dev
- 032615c: added Pagy::I18n deprecation tests
- ebd6151: added deprecation remapping
- e1bd70c: renamed pt-br -> pt-BR
- a77dfcf: fix for sv and sv-SE pluralization
- 6a31db6: Swedish locale: add sv-SE, rename se -> sv (#226)
- 00bd312: bundle update (closes #208, closes #223, closes #224)
- 133da16: Add tutorial link (#222) [ci skip]
Version 3.7.3
Commits
- a2b915e: reorganization of Javascript documentation
- fead55c: Remove duplicated pagination class for Bootstrap (#212)
Version 3.7.2
Changes
- fix for numeric headers in the headers extra
Commits
- 6a93b97: headers must be strings (closes #211)
Version 3.7.1
Changes
- fix for arel count
Commits
Version 3.7.0
Changes
- updated French and Spanish translations
- added Italian translation
- internal renaming
Pagy::Frontend::MARK>Pagy::PAGE_PLACEHOLDER
Commits
- 434912b: updated rubyzip gem
- b627e55: add italian translation (#202)
- 3341dcc: created ITEMS_PLACEHOLDER constant
- 7775155: replaced Pagy::Frontend::MARK with Pagy::PAGE_PLACEHOLDER (MARK is still defined for backward compatibility)
- 439676e: Fixed previous translation for Spanish (#199)
- ee1b1f0: Update fr.yml (#195)
- 8b6f81f: added pagy-cursor link in README
- c290dca: update incorrect tutorial link (#198)
- 77c045d: add: tutorial link in ReadMe - complex search forms (#194)
- 846eece: fix in README.md
- 224748a: fix for resurrected-by-mistake line in README
Version 3.6.0
Changes
- added arel extra
- updated Gemfile for development environment
- docs fixes and improvements
Commits
- af0f189: updated minitest and minitest-reporter gems and removed deprecation
- 6a62de5: updated Gemfile
- 4856782: Arel Extra (#189)
- 2a2d9b0: Revert "Added digital-climate-strike banner"This reverts commit 07f7d9256ef9b1cef1c1eaf6da56ebb03daa19d5.
- b5c2809: docs fixes
- f8e4f42: replaced markdown file link for documentation link in extras
- 6a5c271: updated github-pages gem
- 60d243c: small doc improvement [ci skip]
- 2feb451: docs changes
- 07f7d92: Added digital-climate-strike banner
- 281da85: update grammar (#187)
- 739f032: Update how-to: Correct to require header for API (#188)
Version 3.5.1
Changes
- added support for elasticsearch 7
Commits
- ca736cc: Adding elasticsearch7 support (#185) Fixes #184
- 13b7314: correct typos in docs and initializer (#186) [ci skip]
- 9734ed6: Docs style changes [ci skip]
- fb8bcf4: doc fix for missing :partial key in rendering example (closes #180)
- 7160a18: Minor docs changes [ci skip]
Version 3.5.0
Changes
- Added Korean locale
- Added Catalan locale
- Added metadata extra
- Docs fixes and improvements
Commits
- 2813973: Docs:
- added detailed Quick Start steps (closes #176, closes #177)
- added specific sections for API clients and javascript frameworks
- 43349a8: added metadata extra
- 261e6e6: Add Catalan localization (#178)
- 30ed505: temporarily removed jruby 1.7 and 9.0 rvm from travis - waiting travis to fix their rvms or suggest some work around see issue
- 2863c55: added minitest-reporters gem
- 0b42e5c: Add translation ko.yml for korean (#172)
- da3fc37: minor doc fixes [ci skip]
Version 3.4.1
Changes
- Improvements for searchkick extra
- Added javascript Pagy.version
Commits
- 0ac5c27: refactoring of pagy_search and its usage in order to allow optional term argument for searchkick (#169)
- 389755b: small docs editing [ci skip]
Version 3.4.0
Changes
- Added UIkit nav, nav_js and combo_js helpers and templates.
Commits
- 1eb25ec: Implement UIkit pagination (#164)
Version 3.3.2
Changes
- Fix for #163
- Javascript improvements
Commits
- aff8cbb: better handling of resize listeners; added render function to the pagy element
- c699fe5: fix for javascript/turbolink nav.render firing when element not found (#163)
Version 3.3.1
Changes
Namespacing of all exceptions, still backward compatible with legacy rescues
Commits
- 530cb24: all the exceptions are namespaced and can return more information for easier rescue of special cases
Version 3.3.0
Changes
- Added Bulgarian locale
Commits
- 2c56428: added pluralization comment to bg.yml dictionary
- 7111cec: Bulgarian language yml file. (#162)
- a46f6b5: improved suggestion for headers usage
Version 3.2.1
Commits
- b403a35: improved trim regex: simpler, safer and more tested
- bd3be09: normalized aliasing with alias_method
- 3c60d9b: minor doc fixes
- 9aa1bea: fix for missing "partial" in examples for template usage (#160)
- 405b4d2: reorganization and renaming of test helpers
- 459edaa: improved notes about preventing crawlers to follow look-alike links
- 01c73d3: added search box to docs
Version 3.2.0
Commits
- 2341a83: docs fixes and additions
- 96ad00f: extended trim extra support to all the *_js helpers:
- refactored trim extra
- simplified MARK strings
- use of RegExp patterns in pagy.js
- added and improved tests
Version 3.1.0
Commits
- 1732dee: refactoring of marker and hidden links in *_js helpers:
- MARKER renamed to MARK is simpler, static and hardcoded in pagy.js as well
- removed hidden links to bogus urls that were triggering crawlers to follow (#158)
- pagy_items_selector now works also with trim and in combination with other *nav_js helpers
- updated tests
- aa140e1: doc improvement
- d0e4ba6: a few fixes and doc improvements
- c1ddbd9: Fix typo in docs example (#156)
- e0b2a2b: removed duplication in LEGACY_CHANGELOG
- ecb6822: fix typo in README
Version 3.0.0
Breaking Changes
Refactoring of i18n
- The
zh-cnandzh-hkwere named incorrectly. They have been properly renamed aszh-CNandzh-HK. If you used them, you should update thePagy::I18n.loadstatement. - Removed the plural keys inconsistent with the locale: now the dictionary files are 100% compatible with the I18n gem. If you use custom dictionaries, you should update their entries.
- The
:item_pathvariable has been renamed as:i18n_key: you should search and replace it.
Renamed nav helper methods and files
The javascript-powered helpers (pagy*_responsive_nav, pagy*_compact_nav and items_selector) have been renamed in order to be simpler and more descriptive of their arguments, features and requirements. They have been improved internally, but you need only to search and replace because their usage has not been changed.
Bootstrap Extra
| v2.0+ | v3.0+ |
|---|---|
pagy_bootstrap_responsive_nav :breakpoints |
pagy_bootstrap_nav_js :steps |
pagy_bootstrap_compact_nav |
pagy_bootstrap_combo_nav_js |
Bulma Extra
| v2.0+ | v3.0+ |
|---|---|
pagy_bulma_responsive_nav :breakpoints |
pagy_bulma_nav_js :steps |
pagy_bulma_compact_nav |
pagy_bulma_combo_nav_js |
Foundation Extra
| v2.0+ | v3.0+ |
|---|---|
pagy_foundation_responsive_nav :breakpoints |
pagy_foundation_nav_js :steps |
pagy_foundation_compact_nav |
pagy_foundation_combo_nav_js |
Materialize Extra
| v2.0+ | v3.0+ |
|---|---|
pagy_materialize_responsive_nav :breakpoints |
pagy_materialize_nav_js :steps |
pagy_materialize_compact_nav |
pagy_materialize_combo_nav_js |
Plain > Navs Extra
| v2.0+ | v3.0+ |
|---|---|
pagy_plain_nav (pagy_nav alias) |
- removed - |
pagy_plain_responsive_nav :breakpoints |
pagy_nav_js :steps |
pagy_plain_compact_nav |
pagy_combo_nav_js |
require "pagy/extras/plain" |
require "pagy/extras/navs" |
Semantic Extra
| v2.0+ | v3.0+ |
|---|---|
pagy_semantic_responsive_nav :breakpoints |
pagy_semantic_nav_js :steps |
pagy_semantic_compact_nav |
pagy_semantic_combo_nav_js |
Renamed Pagy::VARS
Pagy::Vars[:breakpoints] has been renamed as Pagy::VARS[:steps]
Renamed items_selector
items_selector has been renamed as items_selector_js. It is also possible to use the i18n_key variable to customize the item name.
Renamed classes and params in helpers
Notice: You can skip the following sections if you did not override any nav helper.
CSS nav classes
The nav CSS classes follow the same renaming rules of the helper methods:
| v2.0+ | v3.0+ |
|---|---|
pagy-bootstrap-responsive-nav |
pagy-bootstrap-nav-js |
pagy-bootstrap-compact-nav |
pagy-bootstrap-combo-nav-js |
pagy-bulma-responsive-nav |
pagy-bulma-nav-js |
pagy-bulma-compact-nav |
pagy-bulma-combo-nav-js |
pagy-foundation-responsive-nav |
pagy-foundation-nav-js |
pagy-foundation-compact-nav |
pagy-foundation-combo-nav-js |
pagy-materialize-responsive-nav |
pagy-materialize-nav-js |
pagy-materialize-compact-nav |
pagy-materialize-combo-nav-js |
pagy-plain-responsive-nav |
pagy-nav-js |
pagy-plain-compact-nav |
pagy-combo-nav-js |
pagy-semantic-responsive-nav |
pagy-semantic-nav-js |
pagy-semantic-compact-nav |
pagy-semantic-combo-nav-js |
CSS JSON tag classes
Renamed first param passed to the pagy_json_tag:
| v2.0+ | v3.0+ |
|---|---|
:responsive |
:nav |
:compact |
:combo_nav |
:items |
:items_selector |
Javascript functions
| v2.0+ | v3.0+ |
|---|---|
Pagy.responsive |
Pagy.nav |
Pagy.compact |
Pagy.combo_nav |
Pagy.items |
Pagy.items_selector |
Dropped marginal methods
Dropped pagy_serialized, pagy_apply_init_tag and PagyInit javascript namespace. They were too basic to be useful as support for javascript powered custom component.
Commits
- df3ebf2: updated performance assets for v3
- 260e7d4: refactoring of i18n:
- I18n gem compliant (removed plural keys inconsistent with the locale)
- added tests for all the pluralization procs
- simplified and normalized Pagy dictionary file
- renamed :items_Path to :collection_key
- added :collection_key lookup for the items_selector_js helper
- 8ebb1ab: refactoring of test coverage:
- replaced SingleCov with SimpleCov for CodeCov integration
- simplified Travis setup
- separate controls of RuboCop, SimpleCov, Oj and CodeCov with dedicated ENV variables
- completed coverage at 100%
- ae3e4bc: removed overridden method and undefined instance variable warnings
- aa1aad9: renamed multi_series > sequels and relative js arguments and variables; renamed :sizes > :steps; updated nav test cases
- 901f779: compact > combo and other changes
- f7425a5: renamed assets according to helper names; reordered and improved nav docs
- ad100eb: renamed plain extra to navs; removed the "plain_" qualifier for the helpers
- 54f4a7e: updated docs and comments
- 25470dd: renamed items_selector > items_selector_js
- d4be9dd: replaced responsive with nav_js; reordered methods and test normalization
- ec7d754: removed warning for locales zh-cn and zh-hk, and properly renamed as zh-CN and zh-HK
- 2548557: simplified support extra (dropped pagy_serialized and pagy_apply_init_tag)
- f82b2e7: fix typo
- 704a4df: add french translation (#154)
- 2f67dfa: UPDATE pagy locales id (#151)
- 15732da: fix for broken migration link (#150)
Version 2.1.5
Changes
- Fix for
pagy_url_forreturning duplicated params - Added "zh-TW" locale
- Deprecated incorrect zh-cn and zh-hk locales in favor of zh-CN and zh-HK locales
Commits
- 62ee172: fixes for pagy_url_for full url gets duplicated page param (#149)
- used concatenated request.
base_url instead of request.url - added better tests
- fixed overriding of pagy_url_for in items extra
- used concatenated request.
- 0bca4af: fix for rubocop offense
- 6b7fe77: deprecated zh-cn and zh-hk locales, normalized as zh-CN and zh-HK
- c28d21a: Added locale zh-TW (#147)
- 95cdf61: docs improvements
- 310c804: Update lib/locales/README.md (#148)
Version 2.1.4
Changes
- Fix for responsive javascript not working with IE
Commits
- 3cce19a: javascript responsive refactoring:
- replaced problematic loop functions with plain for loops
- better naming in responsive function
- shortened rendering time
- simpler doc
- 3eacc8d: better doc examples
- 5c92187: added missing event listeners to auto-incremental javascript example
- 119ba78: fix for support.md auto-incremental javascript example
- 1f376d4: Update support.md (#146) Fix incremental/infinite scroll examples
Version 2.1.3
Changes
- added Swedish locale
Commits
- f0dcac6: docs update
- 9dc8c05: removed tap from Pagy#series
- e237ea6: add translation for Swedish (#145)
- 7d71699: lighter README and a few docs improvements
- f25b5f5: updated support extra examples with pagy_countess
- 6fa1d03: comments and docs updates
- 9f057e6: small improvement for the headers extra doc
- 2c53e76: a few docs changes for the migration guide
- 2a90e6a: stop following the GitFlow conventions (extra complexity for no advantage for this project; too many merge commits; history difficult to follow)
- 198883c: Fix legacy changelog url (#144)
Version 2.1.2
Changes
- Added "Current-Page" header to headers extra
Commits
- 016b377: added Current-Page default header to headers extra
- 4086181: fix compilant > compliant typos in docs
- 5d6edf6: reconciliation between test strings
Version 2.1.1
Changes
- Fix for multiple pagy get wrong url (#143)
- Better documentation for responsive breakpoints (#140)
Commits
- e9f467a: fix for pagy_url_for not working with multiple pagy in the same request (#143)
- 75329b4: better configuration example and documentation for responsive breakpoints (#140)
Version 2.1.0
Changes
- Added headers extra
- Added support for overflow :last_page to searchkick and elasticsearch_rails extras
- Added zh-hk locale
- Better docs
Commits
- 4e83993: updated docs
- 8bd19d6: added headers extra (#141)
- 9a26b04: added support for overflow :last_page to searchkick and elasticsearch_rails extras (#138)
- c5524fc: Add zh-hk language yml file (#139)
- 6d5841b: update travis setup
- 5bd7c0a: updated docs notes for the searchkick and elasticsearch_rails extras
- 0ca5539: updated comments in config/pagy.rb (#138)
Version 2.0.1
Changes
- Fix for missing require in config/pagy.rb and fix for pt-br translation typos
- docs fixes and improvements
Commits
- 4e7b30f: update Repository Info section in README
- 835e8d2: Fix for missing require in config/pagy.rb and fix for pt-br translation typos (#134)
- 8cdffa1: updated consumption chart in README
- 91aa417: replaced efficiency table with resource-consumption chart; other minor fixes
- 964ab24: fix for wrong params in searchkick synopsis example
- 71baf56: added paginate-responder link to the HTTP header in the How to doc (#132)
- 05e218c: fix for indents in searchkick doc
- 7061086: added README comments for the docs/update branch
- b93259c: fix typos in searchkick readme (#129)
- 4156121: added how-to for custom count for custom scopes (#130); other minor adjustments
- 4c7b50a: docs fixes and additions (#128)
Version 2.0.0
Breaking Changes
Renamed methods and files (already deprecated)
The following methods have been renamed. You only need to search and replace, because the functionality has not been changed.
Bootstrap Extra
| Legacy Name | New Name |
|---|---|
pagy_nav_bootstrap |
pagy_bootstrap_nav |
pagy_nav_compact_bootstrap |
pagy_bootstrap_compact_nav |
pagy_nav_responsive_bootstrap |
pagy_bootstrap_responsive_nav |
Bulma Extra
| Legacy Name | New Name |
|---|---|
pagy_nav_bulma |
pagy_bulma_nav |
pagy_nav_compact_bulma |
pagy_bulma_compact_nav |
pagy_nav_responsive_bulma |
pagy_bulma_responsive_nav |
Foundation Extra
| Legacy Name | New Name |
|---|---|
pagy_nav_foundation |
pagy_foundation_nav |
pagy_nav_compact_foundation |
pagy_foundation_compact_nav |
pagy_nav_responsive_foundation |
pagy_foundation_responsive_nav |
Materialize Extra
| Legacy Name | New Name |
|---|---|
pagy_nav_materialize |
pagy_materialize_nav |
pagy_nav_compact_materialize |
pagy_materialize_compact_nav |
pagy_nav_responsive_materialize |
pagy_materialize_responsive_nav |
Navs Extra
| Legacy Name | New Name |
|---|---|
pagy_plain_nav (pagy_nav alias) |
|
pagy_nav_compact |
pagy_plain_compact_nav |
pagy_nav_responsive |
pagy_plain_responsive_nav |
require "pagy/extras/navs" |
require "pagy/extras/plain" |
Semantic Extra
| Legacy Name | New Name |
|---|---|
pagy_nav_semantic |
pagy_semantic_nav |
pagy_nav_compact_semantic |
pagy_semantic_compact_nav |
pagy_nav_responsive_semantic |
pagy_semantic_responsive_nav |
Renamed classes and params in helpers
Notice: You can skip this section if you did not override any nav helper.
CSS nav classes
The nav CSS classes follow the same renaming rules of the helper methods. For example:
pagy-nav-responsive-bootstrap is now pagy-bootstrap-responsive-nav
CSS JSON tag classes
All the JSON tag classes are now pagy-json, and the qualifier of the json (e.g. compact, responsive, ...) is now passed as the first argument in the array content. For example:
<script type="application/json" class="pagy-responsive-json">["#{id}", ...
is now
<script type="application/json" class="pagy-json">["responsive", "#{id}", ...
However the tags have been refactored to use the shared pagy_json_tag helper. For example:
script = pagy_json_tag(:responsive, id, tags, responsive[:widths], responsive[:series])
Pagy I18n
- The
Pagy::Frontend::I18Nis nowPagy::I18n - The
Pagy::I18n.loadmethod accepts params in different format: see the doc
Searchkick Extra
- The
searchkickextra has been refactored and its methods work in a different way: see the doc
Elasticsearch Rails Extra
- The
elasticsearch_railsextra has been refactored and its methods work in a different way: see the doc
Pagy Initializer
The pagy initializer has changed: please replace/update it: pagy.rb
Commits
- a03ff0b: updated README and docs
- 7bb34e3: refactoring of searchkick extra
- 22afe14: refactoring of elasticsearch_rails extra
- fc608e9: setup for ruby 1.9+ and jruby 1.7+
- 7948394: updated magic comments
- d8ce15f: updated Gemfile
- 8ad362d: conditional SingleCov
- 14a7c30: small change in pagy_bootstrap_compact_nav style
- 8550b67: removed fork from tests
- 532743d: simpler overflow module structure (backward compatible)
- 9c1212b: i18n refactoring:
- added multi-language
- simpler I18N format
- faster pagy_t method
- 1f3c86f: fixed warnings and a few backward incompatible statements
- a6a9371: replaced +'...' syntax with EMPTY + '...' syntax for backward compatibility
- 32984a3: removed empty string assignation (simpler and more efficient)
- e61b1e6: Removed deprecations:
- remove deprecation of method extras and extra CSS class in navs in modules
- remove deprecated method from
extras/shared - remove extra CSS class in tests and templates
- remove the extras/navs.rb and DEPRECATIONS.md files
- remove support for overridden legacy helper in
pagy.js - add a note in the GoRails section in the README
- ca18374: Cache gemset for faster Travis builds (#126)
- 71a3e5f: Always return the same object as Pagy.root (#125)* Update copyright notice to 2019 (#121)
Version 1.3.3
Commits
- 11944e4: Fix typo in class name (#122)
- 40ef36d: travis badge links to branches
- 78141a3: Improve default German translation (#120)
- c0fe0df: minor typo corrections (#119)
Version 1.3.2
Changes
- fixed responsive javascript error
Commits
- 332c6a2: fix for responsive javascript error in slow loading pages (#115)
Version 1.3.1
Changes
- fixed issue with items extra rendered after pagy_nav
Commits
- 3ead159: fix for temp items variable in items extra (#117)
Version 1.3.0
Changes
- Added Dutch locale
- Refactoring of plurals
- Javascript refactoring: fixes and improvements
Commits
- 70796d3: Add Dutch language (#116)Added Dutch dictionary
- b112f30: plurals.rb:
- added frozen variables
- added explicit 'zero' for :zero_one_few_may_other
- added :pl pluralization (#111)
- added README.md
- 6cf86af: added docs notes
- b05db4e: added optional target element to Pagy.init for AJAX support
- e35a9ae: refactoring of default element ids for helpers and deprecation:
- default ids are now constant also in different processes and compliant also with older HTML versions
- simpler deprecation code
- cef823c: pagy.js responsive refactoring (#115):
- moved handling of window event listeners into the responsive function
- added resize delay to Pagy.responsive
- a64a8bd: fix for items test
- e9ab4a1: renamed argument items > fetched; removed redundant assignation
Version 1.2.1
Changes
- Improved efficiency for count in backend and extras
Commits
- 01178cb: replaced enumerable #count for #size (suggested in #112)
- 0723228: count (and page) in *get_variables methods are set only when nil (alternative implementation of #112)
Changes
- Deprecation of frontend helpers (see Deprecations)
- Internal refactoring of javascript
- added
supportextra for features like: incremental, infinite, auto-scroll pagination
Commits
- 2bdb1e5: added support extra
- 055af34: added :cycle variable to Pagy
- c1680ec: add JSON/javascript deprecations
- 263c12d: better internal javascript naming
- 910facc: updated tests
- 6e8cde8: refactoring of json tags:
- single "pagy-json" class for all json tags
- removed prefix used for all pagy element ids
- extracted pagy_json_tag from frontend extras
- 98ce8e7: automatic ids based on hash must be strings
- cd8256e: added DEPRECATIONS file
- 6e3e1e4: deprecated and renamed navs helpers in code, tests and docs; renamed navs extension as plain; added :pagy_plain_nav alias of :pagy_nav
- 4bc72af: deprecated and renamed semantic navs in code, tests and docs
- a9c3822: deprecated and renamed materialize navs in code, tests and docs
- 5481f40: renamed foundation templates and updated docs
- f984f83: deprecated and renamed foundation navs in code, tests and docs
- 95045c3: renamed bulma templates and updated docs
- dbad41a: deprecated and renamed bulma navs in code, tests and docs
- e4f859f: renamed bootstrap templates and updated docs
- 35078ab: deprecated and renamed bootstrap navs in code, tests and docs
- 04ec860: added Pagy.deprecate method
Version 1.1.0
Changes
- added
Pagy::Countlesssupport subclass - added
countlessextra integrated with the other extras
Commits
- fa547ad: reworded the doc notice about :pagy_countless_get_items returning an Array; fix typo in comment
- 8368a99: Synopsys > Synopsis
- 1b8a080: a few fixes for the countless tests
- 0bf2f46: Typo fix
- 2f93227: Test coverage for
Pagy::Countless(#108) - c2a25b6: Add some tests for Countless extra (#108)
- 04fa7a2: added countless support to the items extra
- f272faf: added countless support to the overflow extra
- 7b25165: added countless sub-class and extra code
- 37cf51a: series can return an empty array if size is empty
- 7bf9d14: fix for a few missing lines in the extras docs
Version 1.0.0
Breaking Changes
- The "Out Of Range" concept has been redefined as "Overflow" resulting in a few renaming. Since there are no changes in the logic, you can update by just searching and replacing (if present) a few string in your code:
"/out_of_range">"/overflow""OutOfRangeError">"OverflowError"":out_of_range_mode">":overflow""out_of_range?>"overflow?"
Commits
- 431e4db: redefined the "Out Of Range" concept as "Overflow" (#103):
- files: out_of_range* > overflow*
- extra name: out_of_range > overflow
- error class: OutOfRangeError > OverflowError
- module: OutOfRange > Overflow
- VARS: :out_of_range_mode > :overflow
- instance variable: @out_of_range > @overflow
- method: out_of_range? > overflow?
- a0b411a: added README note about semantic versioning
Version 0.23.1
Commits
- e8a2251: fix for ArgumentError feedback in Pagy constructor should show the originally passed offending value (#104)
Version 0.23.0
Changes
- Added German locale
Commits
Version 0.22.0
Changes
- Added Norwegian locale
Commits
- 59064c2: Added Norwegian locale (#100)
Version 0.21.0
Changes
- Added Elasticsearch Rails extra
Commits
- e0acbf6: fix for robocop offenses (#96)
- d082729: Added Elasticsearch Rails extra (#96)
- dd0575a: fix doc typo
- d3510a7: updated comments in plurals.rb
- 5ed458a: added README disclaimer
- 02b0a74: Update link to Semantic-UI pagination
Version 0.20.0
Breaking Changes
- I18n refactoring
- Combo helpers and item selectors have been refactored: you should update your overridden helpers accordingly
- The i18n structure has changed, update your custom i18n locale file
Commits
- bab3bf8: Merge pull request #93 from ddnexus/i18n
- f8017c3: updated config/pagy.rb
- c461885: added ru plural proc
- 5680628: fix for wrong indentation in zh-cn
- 6998932: pagy.yml properly split into separate locale files
- e3048f2: improvements for ja tr and zh-cn
- c1aec4c: removed marginal pagy.nav.current key used only by foundation an fixed consistency in foundation helpers and templates
- 15e413b: refactoring of the composition of i18n strings for compact helpers and items selector
Version 0.19.4
Changes
- added Japanese, Brazilian and Indonesian translations
Commits
- 67f1bb9: reordered translations
- 4ab3438: adding pt-br translation (#87)
- d1f8674: alpha-ordered translations
- 0311c85: Added Indonesian locale (#91)
- ce68624: add japanese translation (#89)
- 5e4f93d: corrected chinese translation (#88)
- 26654d4: updated README
Version 0.19.3
Changes
- added Chinese locale
Commits
Version 0.19.2
Changes
- added Russian locale
Commits
- 099731b: small improvement in i18n docs
- ef77ae2: Added ru translation (#84)
- d4b49d6: Fixed a typo in spanish locale. (#85)
- a91b72a: small description change for items selector UI
- a62b222: small refactoring of the trim extra
- c23505a: fix for doc typo
Version 0.19.1
Changes
- added Spanish locale
Commits
- 6d498a1: Added Spanish locale (#82)
- 65db877: general docs improvements
- 5862b3f: updated README
- 6414395: added GoRails screencast link to README
- a8ad399: docs fixes and improvements
- 435e849: updated docs
Version 0.19.0
Important Changes
- added Semantic extra
Commits
- b65a905: fix for page_link string and conflicts, added compact and responsive navs tests and docs (#73)
- f147cca: Semantic UI nav helper (#73)
- 429ac14: updated pagy.js requirements info
Version 0.18.0
Breaking Changes
- The extras dir has been reorganized:
- the helpers in the
compactandresponsiveextras have been integrated into the respective frontend extras (bootstrap,bulma,foundation,materializeandnavs), so thecompactandresponsiveextras are gone. You should remove them from the pagy.rb initializer, eventually adding thenavsextra if you use its plain helpers. - The
templatesandjavascriptsdirs have been moved tolib. If you use rails and thepagy.jsyou should update theassets.pathsin the pagy.rb initializer.
- the helpers in the
Commits
Version 0.17.0
Important Changes
- added Foundation extra
Commits
- ba7d046: added fixes and improvements for foundation extra:
- d78f85d: Foundation extra (#79)
- 13f37a0: restyling of extras in README, docs and initializer example
Version 0.16.0
Important Changes
- added Searchkick extra
Commits
- 6143f5f: docs fixes
- 5227bd1: added searchkick references in docs, README and initializer example (#75)
- b9acf0c: Searchkick extra (#75)
Version 0.15.1
Important Changes
- small bugs and compatibility fixes
Commits
- 1436833: added Post and Tutorials links and Credits section
- 4e400c6: items are adjusted only for non-empty pages
(avoid sequel error for limit 0) - 3abcc11: fix for sinatra: page_param must be converted to string
- ad8c311: fix for trim extra missing when current page=1
- 6f774d7: added missing doc menu for trim extra
- 5f6de56: added a few tests for the trim extra
Version 0.15.0
Important Changes
- Added Trim extra
Commits
Version 0.14.0
Important Changes
- Added Materialize extra
Commits
- b0e959b: added stars github button to docs
- 1dd38c9: added materialize extra (#44)
- 30c1a57: updated docs
Version 0.13.1
Important Changes
- Improvements and fixes for the out_of_range extra
Commits
- 419af23: better comments and error message for unknown out_of_range_mode variable
- 48fa056: use case (#71)
- 36761a8: fix :last_page mode in out_of_range extra (#70)
- 5958dc5: out_of_range extra improvements (#68)
- 7177cd9: added note about the out_of_range exta to the README
Version 0.13.0
Important Changes
- Added Out Of Range extra
Commits
- c52db2a: added out_of_range extra (#68)
- 37119ee: fixes for bulma extra in initializer_example.rb and docs
- 05729f6: removed redundant condition in Pagy initialize
- 2e75247: small fixes in CHANGELOG
- 3d732dd: docs for empty page OutOfRangeError (#69)
- a3be52e: Fixed screenshot name for compact bulma extra (#67)
Version 0.12.0
Important Changes
- Added Bulma extra
- Added Turkish language in pagy dictionary
- Improved consistence and compatibility in extras
Commits
- 8fc91df: fix for "area" typos in bulma extra (#62) and consistency improvement across responsive helpers
- bb0060f: fix for window event listeners persisted by turbolinks (#64)
- d759f91: Bulma extra (#62)
- 9f09837: Fixed typo in some extras usage (#63)
- 2ce572a: Added Turkish locales (#58)
- dd361e1: replaced Array.from in pagy.js for extended compatibility
- bb1243d: fix typos
- da34b94: fix typo (#61)
- cdab354: added better I18n comments in initializer_example.rb
Version 0.11.2
Commits
- 76fc273: used merge! in place of **
Version 0.11.1
Important Changes
- All tests has been converted to the spec syntax
Commits
- b14f446: converted tests to spec syntax
- 0422568: cleanup of i81n plurals in code and docs
- 5a2db16: added a few missing references to docs
- 6028980: enabled rubocop Naming/UncommunicativeMethodParamName
- 1de470b: small improvements and fixes for docs
- 228109e: fix for typos
- 0a1ed94: updated initializer_example.rb
Version 0.11.0
Breaking Changes
- The
pagy_nav_bootstrap_compactandpagy_nav_bootstrap_responsivehelpers have been renamed aspagy_nav_compact_bootstrapandpagy_nav_responsive_bootstrapto keep the consistency with the extras structure (and support the consistency of future framework additions). Please, rename them accordingly. - The
Pagy::Frontend::I18N.load_filehas been renamed asPagy::Frontend::I18N.loadand expects a hash as the argument. See the I18n doc. - The seldom used
Pagy::Frontend::I18N[plurals]has been renamed asPagy::Frontend::I18N[plural]. See the I18n doc. - Please, update your initializer file to the new initializer_example.rb
Commits
- 826798b: refactoring of I18N constant: added support for multiple static languages and plural rules
- b78b71e: better naming of json classes
- ea7c22b: breaking change for compact and responsive extras: renaming of pagy_nav_bootstrap_* helpers to pagy_nav_*_bootstrap, consistent with extras structure
- 7d1a573: internal consistency renaming of local/test variables; minor fixes and improvements
Version 0.10.1
Commits
- 8ca5013: doc improvements
- 99081ee: small performance improvement for #51 and updated doc
- 5863ceb: add support for counting grouped collections (#51)
Version 0.10.0
Breaking Changes
- The javascript used by the
compact,itemsandresponsiveextras has been refactored in order to avoid any usafe-inline vulnerability. The javascript files have been replaced by one shared file, and require to set an event listener or run a function on window load. See the commit below and the javascript doc for details.
Commits
- 50e304b: javascript refactoring in order to avoid any usafe-inline vulnerability (#52):
- removed inline scripts from all extras
- one single pagy.js file shared among all the extras
- the Pagy.init function should be executed at document load
- updated tests and docs
- 32d0afc: doc fix: UI selector > selector UI
Version 0.9.2
Important Changes
- 100% test coverage for core code and extras
Commits
- c11dfcc: updated README
- f8728e7: added responsive extra tests
- 14ea356: added compact extra tests
- 2ac743c: added bootstrap extra test
- 159b65e: added i18n extra tests
- 4449c95: normalization of indentation and empty lines
- 9afa9d9: Default Frozen Strings for Ruby Files (#49)
- 036c87f: Fix typo in :page_param configuration (#48)
Version 0.9.1
Important Changes
- Improved the Pagy::OutOfRangeError exception, now storing the failed Pagy object
Commits
- 9817659: improved OutOfRangeError exception (storing the failed Pagy object)
- 7195229: a few minor consistency fixes for the initializer_example.rb
- 00cd5bb: Fix typo (#45)
- 8b3a733: fix for header level in README
Version 0.9.0
Important Changes
- Improvements for compact extra
- Refactoring of test structure and tasks
- Added items extra: Allow the client to request a custom number of items per page with an optional selector UI
Commits
- 45dd700: added array extra tests
- 623ce9e: Added items extra and tests
- 5902e8a: passed instance variables are not deleted from the vars hash
- e2efb89: refactoring of test structure
- 1cc335b: documentation updates
- 42ba053: improved pagy-compact.js
- 8c20fa2: Enable support for return key inside Pagy compact input (#43)
- d4b751c: Documentation updates
- 9f0dec9: fix for broken links in docs
- c41e823: additions and normalization of documentation and comments
- 38f9a49: fix for broken links in readme
Version 0.8.6
Commits
- 0db9125: minor documentation improvements
- 8a0a5a8: broader parallel assignment in methods (improved performance)
- 18baa8b: small optimization (used a few less objects)
- 1d16e3d: documentation additions
- 62c420d: updated doc and charts
Version 0.8.5
Important Changes
- Fix for I18n exception on startup
Commits
- 31b815d: fix for I18n exception on startup (#41)
Version 0.8.4
Important Changes
- Improved readability and memory allocation
- All the core methods are tested
- Better documentation
Commits
- c25493a: added backend tests
- 48dbe17: docs small fixes and improvements
- 5e9b7d4: add Pagy::VARS[:item_path] empty default
- ce8d09a: add Pagy::VARS[:anchor] empty default
- 8789edd: improve readability of pagy_link_proc (#40):
- remove conditions to avoid extra spaces inside the html tags
- add Pagy::VARS[:link_extra] empty default
- 2f0d384: docs additions
Version 0.8.3
Important Changes
- Refactoring of
I18Nto fix #39
Breaking Changes
Pagy::I18Nhas been moved toPagy::Frontend::I18N: you should update the initializer in case you set any of thePagy::I18Nvariable.
Commits
- d85791e: Refactoring I18N to fix #39:
- moved I18N from Pagy to Pagy::Frontend - I18N_DATA moved to Pagy::Frontend::I18N[:data]
- I18N[:file] removed
- added I18N.load_file method
- updated initializer and doc
- 504b943: added missing tests to frontend_test.rb
- 6168df3: use actionable code coverage (#29)
Version 0.8.2
Important Changes
- Fix for PostgreSQL:
collection.count(:all)
Commits
- 8a204dc: fix for count in Pagy::Backend (#36)
- 29ed221: added test_check_variable_defaults
- 1263540: indentation fixes for tests
- a927d57: improve testability by sorting tests into files that mirror lib + group by method (#37)
- 5a5178b: docs markdown normalization and README editing
- 11fbc49: examples was using responsive instead of i18n (#35)
- b9517d3: docs small fixes and improvements
- 8bc6900: fix for typos and omissions in initializer_example.rb
- a09558e: avoid uncoverable code by not using gemspec in Gemfile (#33)
- a585fe6: clean up gemspec (#32)
- ae48f13: test on all supported ruby versions and split out rubocop (#30)
Version 0.8.1
Important Changes
- Added
:paramsand:anchorvariables to control the generation of arbitrary URLs per pagy instance
Commits
- d185461: added :params and :anchor variables to control the generation of arbitrary URLs per pagy instance
- 62fd6c8: better forward improvements with pagy_url_for receiving the pagy instance instead of the single pagy_param
- 748de0d: readme and changelog improvement
Version 0.8.0
Important Changes
- Added an initializer_example.rb that you can use as an easy template for Pagy configuration
- Integrated extras from
pagy-extrasgem into Pagy, now optionally required in the initializer - Refactored I18n: simpler code and simpler configuration now based on the
I18nextra - Reorganized documentation and added a few more how-to topics
- Added the
:page_paramvariable used to get the page number from and create the URL for the page links
Breaking Changes
- Extra are now integrated in Pagy. The
pagy-extrasgem has been discontinued: you should remove it and update your code as indicated here - Pagy I18n has been refactored and it's simpler to use. The main change is that the
Pagy::I18N[:gem]variable has been removed, so if you want to use theI18ngem in place of the internal Pagy implementation you need just torequire 'pagy/extras/i18n'in your initializer. (see the I18n doc) pagy_url_fornow requires the pagy argument and it's called with 2 params: if you have overridden it, you should add the extra param.pagy_get_varsnow requires the vars argument and it's called with 2 params: if you have overridden it, you should add the extra param.pagy_array_get_varsnow requires the vars argument and it's called with 2 params: if you have overridden it, you should add the extra param.
Commits
- 3e2ad90: added CHANGELOG.md with the latest few versions (#23)
- f42811d: implemented :page_param (#20)
- 9040593: added doc about skipping single pages navs
- 605169a: added initializer_example.rb
- daa2c1b: I18n refactoring:
- simplified the pagy_t definition
- simplified the configuration of I18n now using the I18n extra to override the pagy_t
- modules are now required and not autoloaded
- updated doc
- 9b0d420: style cleanup (#24)
- dbc5a05: Add prev/next links to compact Bootstrap nav and improve HTML semantics (#21)
- f764cc1: refactoring extras:
- moved pagy-extra files into the extras dir - moved the templates dir into the extras dir
- updated the documentation
- befe92d: Fixes Travis Badge (#25)
- 3862d26: Travis (#22)
- 7050ee0: basic rubocop setup (#18)
- 7aee689: small docs improvements
Version 0.7.2
Commits
Version 0.7.1
Commits
- 92260b5: docs and comments refactoring, also updated for pagy-extras v0.2.0
- 46f235e: Remove a couple of Range allocations (#10)
- 39c5470: Only use and/or keywords for control flow (#12)
- 26bb29c: fix for last page items adjusted to 0 (#3)
- 860c579: small improvement: to_i called only once in core variables set
- b18f254: Merge pull request #5 from artinboghosian/patch-1
- 03d6ee8: Update README.md
- 358a806: a couple of links added to the doc
- fac1f34: docs small fixes and improvements
Version 0.7.0
Commits
- e480d04: better handling of blank core variables
- b56ef9e: docs fixes and improvements
- 987be15: I18N[:plurals] proc uses symbols and returns a frozen string
- 6ea7a48: changes for PR #2: - use of local variable zero_one instead of constant I18N_PLURALS - VARS cannot be frozen
- fb8975b: Freeze class immutable constant variable at first
Version 0.6.0
Commits
- ec8e268: created pagy-extras gem:
- moved pagy_nav_bootstrap method and templates
- updated docs files (fixes and use of relative links)
- facc4c3: unescaped notation for all erb usage
- 26c068f: moved require yaml in Frontend
- f5782d8: added css classes to pagy helper navs
- cee02c6: helper tags are strings
- 4788c3c: grouped the variables :initial, :before, :after and :final into one single :size array; #series can work with different sizes
- e610b82: minor docs fixes
Retype.Yml (`docs/retype.yml`)
start:
pro: true
open: false
input: .
output: .public
url: https://ddnexus.github.io/pagy/
include:
- "/assets/nav.html.erb"
- "/gem/apps/enable_rails_page_segment.rb"
- "/gem/config/pagy.rb"
- "/gem/locales/en.yml"
- "/gem/stylesheets/pagy.css"
- "/gem/stylesheets/pagy-tailwind.css"
exclude:
- "CLAUDE*.md"
branding:
title: Pagy
logo: assets/images/pagy-the-frog.png
label: 43.8.1
colors:
label:
text: "#ffffff"
background: "#1f7a1f"
meta:
title: " 💚 Pagy"
links:
- text: GitHub
link: https://github.com/ddnexus/pagy
icon: mark-github
target: blank - text: Issues
link: https://github.com/ddnexus/pagy/issues
icon: issue-opened
target: blank - text: Q&A
link: https://github.com/ddnexus/pagy/discussions/categories/q-a
icon: comment-discussion
target: blank - text: Discussions
link: https://github.com/ddnexus/pagy/discussions
icon: comment-discussion
target: blank
search:
mode: full
backlinks:
enabled: false
breadcrumb:
home: Pagy
separator: ":icon-arrow-right:"
theme:
base:
base-color: "#008000"
dark:
base-color: "#7cb342"
lastUpdated:
date:
enabled: true
source: committer
nav:
mode: stack
icons:
mode: pages
nextprev:
mode: exclude
footer:
copyright: "© 2017-{{ date.now.year }} • Domizio Demichelis • MIT License"
Guides Choose Right (`docs/guides/choose-right.md`)
label: Choose Right icon: thumbsup order: 95
:icon-thumbsup: Choose the right tool
Pagination just means retrieving a (potentially big) collection of items in small sequential chunks (pages).
Pagy offers four different pagination techniques, each implementing different types of paginators. Choose the right one to ensure the best performance and workflow.
Pagination Types
:icon-move-to-end: OFFSET {#offset}
The most common pagination technique is counting the collection items (COUNT DB query), using the count to calculate where the specific pages start (i.e., OFFSET) and retrieving only the LIMIT items for that page (OFFSET+LIMIT DB query).
It is straightforward to understand and set up and very versatile for the UI, but it also has a few shortcomings.
==- Shortcomings
- DB Performance
- Counting records might be quite expensive in terms of execution time and DB load. The standard OFFSET pagination causes the DB to count twice per page: once for the total records and another for the records to skip.
- Data Shift
- If records are created or deleted during browsing, the calculated OFFSET may become inconsistent. The user may see previous records again or miss records entirely.
- Notice that querying the precise count for each page DOES NOT fix the data-shift problem.
!!!tip For better DB performance with OFFSET...
- Use the :countish or :countless paginators to improve the DB performance up to two times.
- Paginate only MAX records when possible.
!!!
==- Paginators [!badge variant="contrast" size="xs" corners="pill" text="3"] {#offset-paginators}
{.list-icon}
- :icon-move-to-end: :offset
- :icon-check-circle: Best for: Standard App (Small Data)
- :icon-thumbsup: Pros: Simple setup, full UI support
- :icon-thumbsdown: Cons: Slow on big tables (two queries per page), data-shift
{.list-icon}
- :icon-move-to-end: :countish
- :icon-check-circle: Best for: Standard App (Large Data)
- :icon-thumbsup: Pros: Same as
:offset, but far better performance than:offset(memoizes the total count) - :icon-thumbsdown: Cons: Same as
:offset, thecountmay become stale (likely a negligible side effect)
{.list-icon}
- :icon-move-to-end: :countless
- :icon-check-circle: Best for: API, Infinite Scroll
- :icon-thumbsup: Pros: Fastest in the offset family (only one query per page)
- :icon-thumbsdown: Cons: Same as
:offset, thecountis alwaysnil, UI support with a few limitations
===
:icon-key: KEYSET {#keyset}
The KEYSET pagination technique allows the fastest and lightest DB performance. It does not count the (ordered) collection (which makes it faster), nor does it calculate any numeric page pointers in advance (which avoids the data-shift during browsing). It just uses the values in the last record of the page to retrieve the next page.
==- Shortcomings
- It knows only the current page and the pointer to the next page.
- Page pointers are encoded strings and the count is not known.
- It supports only APIs and infinite scrolling.
!!!tip For UI support with KEYSET pagination...
Use the :keynav_js paginator.
!!!
==- Paginators [!badge variant="contrast" size="xs" corners="pill" text="2"] {#keyset-paginators}
{.list-icon}
- :icon-key: :keyset
- :icon-check-circle: Best for: API, Infinite Scroll
- :icon-thumbsup: Pros: Fastest paginator, no data-shift, fastest single query per page
- :icon-thumbsdown: Cons: Very limited UI support, appropriate DB indices required
{.list-icon}
- :icon-key: :keynav_js
- :icon-check-circle: Best for: Standard App (Large Data)
- :icon-thumbsup: Pros: All the pros of
:keyset+:countless, numeric pages - :icon-thumbsdown: Cons: Same as
:countless, requires JavaScript Support (or it falls back to the:countlesspaginator)
===
:icon-calendar: TIME-RANGE {#time-range}
This hybrid technique filters by a specific time period (Year, Month, Day, etc.) and applies the offset paginator within that period.
==- Paginator [!badge variant="contrast" size="xs" corners="pill" text="1"]
{.list-icon}
- :icon-calendar: :calendar
- :icon-check-circle: Best for: Time-series, log collections
- :icon-thumbsup: Pros: Natural navigation for date-based data
- :icon-thumbsdown: Cons: The setup for the UI is more involved
===
:icon-search: SEARCH {#search}
Pagy supports ElasticsearchRails, Meilisearch, ActiveSearch, Searchkick, and TypesenseRails.
The search paginators get the count, limit and results provided by the search platform. Pagy acts as an interface to these underlying gems, using the OFFSET technique, without its shortcomings.
==- Paginators [!badge variant="contrast" size="xs" corners="pill" text="5"]
{.list-icon}
- :icon-search: :elasticsearch_rails
:icon-search: :meilisearch
:icon-search: :rails_active_search
:icon-search: :searchkick
:icon-search: :typesense_rails- :icon-check-circle: Best for: Search Results
- :icon-thumbsup: Pros: Leverages the engine's native response
- :icon-thumbsdown: Cons: None (simple interface with the search platform gems)
===
Guides How To (`docs/guides/how-to.md`)
label: How To order: 90 icon: tools
:icon-tools: How To
This page provides practical tips and examples to help you use Pagy efficiently.
==- Choose the right pagination technique
Check the Choose Right Guide
==- Control the items per page
Fixed
: Set the :limit option to the number of items to serve with each page.
Requestable
: Set the :client_limit option to allow the client to request up to the :client_limit. If the client omits to request a specific limit, pagy will fall back to its regular behavior. See also Customize the URL keys below.
Interactive
: Use the limit_tag_js helper to provide a UI selector to the user.
==- Customize the URL keys
- Set
page_key: 'custom_page'to customize URL generation, e.g.,?custom_page=3. - Set the
:limit_keyto customize thelimitparam the same way. (Only useful if:client_limitis allowed).
See URL Options
==- Control the pagination bar
You can customize the number and position of page links of the series_nav and series_nav_js navigation bars using:
- The :slots and :compact options.
- Overriding the
seriesmethod for full control over the pagination bar.
==- Force the :page
Pagy retrieves the page from the 'page' request params hash. To force a specific page number, pass it directly to the pagy method. For example:
@pagy, @records = pagy(:offset, collection, page: 3) # force page #3==- Handle user input
See Safety
==- Customize the ARIA labels
You can customize the aria-label attributes of any *nav* helper by passing the :aria_label option to the helper.
You can also replace the pagy.aria_label.nav strings in the dictionary, as well as the pagy.aria_label.previous and the pagy.aria_label.next.
See ARIA.
==- Paginate with JSON:API nested URLs
Enable jsonapi: true, optionally providing :page_key and :limit_key:
# JSON:API nested query string: E.g.: ?page[number]=2&page[size]=100
@pagy, @records = pagy(:offset, collection, jsonapi: true, page_key: 'number', limit_key: 'size')==- Customize the URL query
See the :querify Option
==- Add a URL fragment
See the URL Options
==- Add HTML attributes to the anchor tags (links)
Pass the :anchor_string option to the helper. It's especially useful for adding data-turbo-* or data-* Stimulus attributes.
==- Customize CSS styles
Pagy includes different formats of stylesheets for customization, as well as styled nav tags for :bootstrap and :bulma.
You can also override the specific helper method.
:::
==- Override the element "style" attribute
The input_nav_js and limit_tag_js use inline style attributes. You can override these rules in your stylesheet files using the [style] attribute selector and !important. Below is an example of overriding the width of an input element:
.pagy input[style] {
width: 5rem !important; /* just a useless example */
}:::
==- Override pagy methods
- Identify the method file's path in the gem
libdir (e.g., 'pagy/...'). - Note the name of the module where it is defined (e.g.,
Pagy::...).
Copy and paste the original method in the Pagy Initializer
require 'pagy/...' # path to the overridden method file
module MyOverridingModule # wrap it with your arbitrarily named module
def any_method # Edit or define your method with the identical name
# Custom logic here...
super
# Custom logic here...
end
end
# prepend your module to the overridden module
Pagy::AnyModule.prepend MyOverridingModuleIf you need assistance, ask in the Q&A discussions.
==- Paginate an array
Simply pass it as the collection: pagy(:offset, my_array, **options)
==- Paginate ActiveRecord collections
Pagy works seamlessly with ActiveRecord collections, but certain collections may require specific handling:
:::
==- :icon-database: Grouped collections
For better performance of grouped counts, you may want to use the :count_over option.
==- :icon-database: Decorated collections
Do it in two steps:
Get the page of records without decoration
@pagy, records = pagy(:offset, Post.all)Decorate the retrieved records
@decorated_records = records.decorate # or YourDecorator.method(records), whatever works==- :icon-database: Custom scope/count
If the default pagy doesn't get the right count:
# pass the right count to pagy (that will directly use it skipping its own `collection.count(:all)`)
@pagy, @records = pagy(:offset, custom_scope, count: custom_count) # Example implementation==- :icon-database: Ransack results
Ransack's result method returns an ActiveRecord collection that is ready for pagination:
q = Person.ransack(params[:q])
@pagy, @people = pagy(:offset, q.result)==- :icon-database: PostgreSQL collections
Always ensure your collections are ordered!
:::
==- Paginate for generic API clients
Explore the following options:
- :keyset paginator
- headers_hash helper
:client_limitpaginator option:jsonapipaginator option
==- Paginate for JavaScript frameworks
You can send selected @pagy instance data to the client as JSON using the data_hash helper, including pagination metadata in your JSON response.
==- Paginate search platform results
See these paginators:
==- Paginate by date
Use the :calendar paginator for pagination filtering by calendar time units (e.g., year, quarter, month, week, day).
==- Paginate multiple independent collections
When you need to paginate multiple collections in a single request, you need to explicitly differentiate the pagination objects. Here are some common methods to achieve this:
:::
==- :icon-light-bulb: Override the request path
By default, Pagy generates links using the same path as the request path. To generate links pointing to a different controller or path, explicitly pass the desired :path. For example:
def index
@pagy_foos, @foos = pagy(:offset, Foo.all, path: '/foos')
@pagy_bars, @bars = pagy(:offset, Bar.all, path: '/bars')
end<%== @pagy_foos.series_nav %>
<%== @pagy_bars.series_nav %>==- :icon-light-bulb: Use separate Turbo Frame actions
If you're using hotwire (turbo-rails being the Rails implementation), another way of maintaining independent contexts is using separate Turbo Frame actions. Just wrap each independent context in a turbo_frame_tag and ensure a matching turbo_frame_tag is returned:
<%# movies/index.html.erb %>
<%# movies#bad_movies %>
<%= turbo_frame_tag "bad_movies", src: bad_movies_path do %>
<%= render "movies_table", locals: {movies: @movies}%>
<%== @pagy.series_nav %>
<% end %>
<%# movies#good_movies %>
<%= turbo_frame_tag "good_movies", src: good_movies_path do %>
<%= render "movies_table", locals: {movies: @movies}%>
<%== @pagy.series_nav %>
<% end %>def good
@pagy, @movies = pagy(:offset, Movie.good, limit: 5)
end
def bad
@pagy, @movies = pagy(:offset, Movie.bad, limit: 5)
end==- :icon-light-bulb: Use the root_key option
By default, pagy creates flat URLs for its links. If you need to handle multiple pagy instances in the same request, you can nest the :page and (if you use it) the :limit params by passing the :root_key option to the paginator:
def index
@pagy_stars, @stars = pagy(:offset, Star.all, root_key: 'stars')
@pagy_nebulae, @nebulae = pagy(:offset, Nebula.all, root_key: 'nebulae')
end==- :icon-light-bulb: Use different page keys
You can also paginate multiple models in the same request by simply using a different :page_key for each instance:
def index
@pagy_stars, @stars = pagy(:offset, Star.all, page_key: 'pagy_stars')
@pagy_nebulae, @nebulae = pagy(:offset, Nebula.all, page_key: 'pagy_nebulae')
end:::
==- Paginate only MAX records
You may want to limit the availability of your records either for speeding up the DB queries (especially useful with OFFSET paginators with big tables), or simply to avoid exposing all your data to scrapers.
The best way to ensure it is to create a limited collection using an ActiveRecord Virtual Table:
max_records = 10_000
collection = Product.where(...).limit(max_records) # Add the max_records limit to your collection
limited = collection.from(collection, :products) # Create a limited collection using the :products Virtual Table
@pagy, @records = pagy(:offset, limited, **options) # Paginate the limited collection!!!success
- It works with all OFFSET and KEYSET paginators.
- It produces faster COUNT and OFFSET queries, limiting the table scan.
- It enforces strict control over the quantity of records you expose.
!!!
==- Paginate collections with metadata
When your collection is already paginated and contains count and pagination metadata, you don't need any pagy* controller method.
For example, this is a Tmdb API search result object, but you can apply the same principle to any other type of collection metadata:
#<Tmdb::Result page=1, total_pages=23, total_results=446, results=[#<Tmdb::Movie ..>,#<Tmdb::Movie...>,...]...>As you can see, it contains the pagination metadata that you can use to set up the pagination with pagy:
# get the paginated collection
tobj = Tmdb::Search.movie("Harry Potter", page: params[:page])
# use its count and page to initialize the @pagy object
@pagy = Pagy::Offset.new(count: tobj.total_results, page: tobj.page, request: Pagy::Request.new(request: request))
# set the paginated collection records
@movies = tobj.results==- Skip single page navs
Unlike other gems, Pagy does not decide for you that the nav of a single page of results must not be rendered. You may want it rendered... or maybe you don't. If you don't:
<%== @pagy.series_nav if @pagy.last > 1 %>==- Maximize performance
- Consider the paginators:
- Consider the helpers:
- When possible:
==- Handle Pagy exceptions
:::
==- :icon-stop: Pagy::OptionError
It is a subclass of ArgumentError that offers information to rescue invalid options. For example: with rescue Pagy::OptionError => e you can get access to a few readers:
e.pagythe pagy objecte.optionthe offending option symbol (e.g.:page)e.valuethe value of the offending option (e.g.-3)
==- :icon-stop: Pagy::RangeError
With the OFFSET pagination technique, users/clients may request a page beyond the end of the collection (e.g., when some records got deleted and a user follows a stale page link).
By default, Pagy doesn't raise any exceptions for requesting an out-of-range page. Instead, it does not retrieve any records and serves the navs as usual, so the user can visit a different page.
Sometimes you may want to take a different action, so you can set the option raise_range_error: true, rescue it and do whatever fits your app better. For example:
rescue_from Pagy::RangeError, with: :redirect_to_last_page
private
def redirect_to_last_page(exception)
redirect_to url_for(page: exception.pagy.last), notice: "Page ##{params[:page]} is out-of-range. Showing page #{exception.pagy.last} instead."
end:::
==- Test with Pagy
- Pagy has 100% test coverage.
- You only need to test pagy if you have overridden methods.
==- Use your own pagination templates
!!!warning Warning!
The pagy nav helpers are not only a lot faster than templates, but they also accept dynamic arguments and comply with ARIA and I18n standards.
Using your own templates is possible, but it's likely just reinventing a slower wheel.
!!!
If you really need to use your own templates, you absolutely can.
Here is a static example that doesn't use any other helper or dictionary file for the sake of simplicity; however, feel free to add your dynamic options and use any helper and dictionary entries as you need:
:::code source="/assets/nav.html.erb" :::
You can use it as usual: just remember to pass the :pagy local set to the @pagy object:
<%== render file: 'nav.html.erb', locals: {pagy: @pagy} %>!!!
You may want to look at the actual output interactively by running:
pagy demo...and point your browser to http://127.0.0.1:8000/template.
!!!
==- Use Pagy with non-rack apps
For non-rack environments that don't respond to the request method, you should pass the :request option to the paginator.
==- Use pagy outside controllers or views
The pagy method needs to set a few options that depend on the availability of the self.request method in the class/module where you included it.
For example, if you call the pagy method for a model (that included the Pagy::Method), it would almost certainly not have the request method available.
The simplest way to make it work is as follows:
include Pagy::Method
def self.paginated(view, my_arg1, my_arg2, **)
collection = ...
view.instance_eval { pagy(:offset, collection, **) }
end<% pagy, records = YourModel.paginated(self, my_arg1, my_arg2, **options) %>==- Handle POST requests (server side)
You may need to POST a very complex search form and paginate the results. Pagy produces nav tags with GET links, so here is a simple way of handling it.
You can start the process with your regular POST request and cache the filtering data on the server. Then, using the regular GET pagination cycle, pass only the cache key as a param (which avoids sending the actual filters back and forth).
Here is a conceptual example using the session:
require 'digest'
def filtered_action
pagy_options = {}
if params[:filter_key] # retrieve already cached filters
filters = session[params[:filter_key]]
else # store new filters
filters = params[:filters] # your filter hash
key = Digest::SHA1.hexdigest(filters.sort.to_json)
session[key] = filters
pagy_options[:querify] = ->(query_hash) { query_hash.merge!(filter_key: key) }
end
collection = Product.where(**filters)
@pagy, @records = pagy(:offset, collection, **pagy_options)
end!!!success Notice: ensure a server-side storage
If you use the session for caching, configure it to use ActiveRecord, Redis, or any server-side storage.
!!!
===
{{ include "snippets/ask-for-support" }}
Guides Index.Yml (`docs/guides/index.yml`)
label: Guides
icon: north-star
order: 100
expanded: true
Guides Migration Guide (`docs/guides/migration-guide.md`)
label: Migrate Legacy Pagination icon: paper-airplane order: 80
:icon-paper-airplane: Migrate WillPaginate/Kaminari
This page covers most of the standard changes you need to make in order to migrate from legacy pagination.
Steps
The Pagy API is quite different from other pagination gems; however, if you split the process into the following general steps, it should be quite simple.
Remove the old code
==- {{ include "snippets/mini-step" step: "1" }} Preparation
- Uninstall the legacy gem and replace it with
gem "pagy"in theGemfile. - Add the
include Pagy::Methodstatement to the application controller.
==- {{ include "snippets/mini-step" step: "2" }} Application-wide search and replace
- Search for the class name of the legacy gem, for example
WillPaginateorKaminari. You should find most of the code related to the global gem configuration or monkey patching. - Remove all the legacy settings of the old gem.
==- {{ include "snippets/mini-step" step: "3" }} Clean up the models
Look for terms like per_page, per, and similar, as these are configuration settings. Include them in the appropriate paginator call in the controller (e.g., pagy(:offset, collection, limit: 10)) or globally in the Pagy initializer (e.g., Pagy::OPTIONS[:limit] = 10).
If the app uses the page scope in model methods or scopes, remove it, along with the argument used to pass the page number, while preserving the rest of the scope. Locate where the app applies this paginated scope in the controllers and replace it with the scope in a paginator statement. For example:
#@records = Product.paginated_scope(params[:page])
@pagy, @records = pagy(:offset, Product.non_paginated_scope)==- {{ include "snippets/mini-step" step: "4" }} Search and replace in the controllers
In controllers, legacy pagination statements generally map directly to Pagy, making them straightforward to convert.
Search for statements with keywords like page and paginate and use the pagy(:offset, ...) paginator instead. For example:
#@records = Product.some_scope.page(params[:page])
#@records = Product.paginate(:page => params[:page])
@pagy, @records = pagy(:offset, Product.my_scope)
#@records = Product.some_scope.page(params[:page]).per(15)
#@records = Product.some_scope.page(params[:page]).per_page(15)
#@records = Product.paginate(page: params[:page], per_page: 15)
@pagy, @records = pagy(:offset, Product.all, limit: 15)==- {{ include "snippets/mini-step" step: "5" }} Search and replace in the views
Similarly, in views, legacy pagination statements typically correspond directly to Pagy, simplifying conversion.
Search for statements with keywords like will_paginate and paginate and use one of the series_nav methods. For example:
<%= will_paginate @records %>
<%= paginate @records %>
<%== @pagy.series_nav %>===
Find the remaining code
If the app has tests, it's time to run them. If not, start the app and navigate through its pages.
If any legacy code remains, it will raise an exception. Remove the old code and retry until no exceptions occur.
Fine-tuning
Once the app displays pagination correctly, customize Pagy as needed (see Stylesheets).
If the previous pagination used custom elements (e.g., custom params, URLs, links, HTML elements, etc.), adjustments may be required for compatibility. Take a look at the topics in the How To docs: they should cover most of your custom needs.
!!!tip
If the app uses pagination from Bootstrap or Bulma frameworks, the existing CSS should function seamlessly with Pagy navigation helpers.
!!!
{{ include "snippets/ask-for-support" }}
Guides Pagy Next (`docs/guides/pagy-next.md`)
label: Use Pagy NEXT
order: 60
icon: zap
nav:
badge:
text: "≈ 44"
variant: info
:icon-zap: Pagy NEXT
!!!tip You can use the NEXT version NOW!
Just edit the Gemfile...
- gem 'pagy', '~> 43.8' # MINOR version restriction
+ gem 'pagy', '~> 43.8.1', require: 'pagy/next' # PATCH version restriction + pagy/next entry pointAs an alternative (without Gemfile changes), ensure the environment variable PAGY_NEXT=true is set BEFORE pagy is required.
$ PAGY_NEXT=true irb
>> require 'pagy'
=> true
>> Pagy::VERSION
=> "43.8.1.next"!!!
How does it work?
Pagy NEXT is the code that will be released as the next MAJOR version. It is already implemented and available in the current version; however, it is overridden with the legacy code and deprecation warnings to respect the SemVer contract.
Pagy NEXT provides an opt-in mechanism to bypass the legacy layer entirely. By using require: 'pagy/next' or setting PAGY_NEXT=true, you effectively run the next MAJOR version's code today.
How should you maintain it?
This "early access" mode is lighter and faster, but requires immediate adherence to the latest API changes.
!!!warning Adjust the gem update policy!
- Use a stricter PATCH version restriction (e.g., replace
~> 43.8with~> 43.8.1). - Follow the Deprecations Instructions after
bundle updateinvolving MINOR or MAJOR releases.
!!!
With the PATCH version restriction, Bundler will automatically update only PATCH releases, ensuring your NEXT code won't break on update. However, remember to manually check bundle outdated more often to avoid missing MINOR or MAJOR releases.
Guides Quick Start (`docs/guides/quick-start.md`)
label: Quick Start order: 100 icon: rocket
:icon-rocket: Quick Start
!!!question Migrating from another pagination gem?
Check the Migration Guide first.
!!!
Steps
Install it...
gem 'pagy', '~> 43.8' # MINOR version restriction, to avoid breaking changesTry it...
{{ include "snippets/run-app" app: "demo" }}
Use it...
=== {{ include "snippets/mini-step" step: "1" }} Include the pagy method where you are going to use it (usually ApplicationController):
include Pagy::Method=== {{ include "snippets/mini-step" step: "2" }} Use it to paginate any collection with any technique:
@pagy, @records = pagy(:offset, Product.some_scope, **options) # :offset paginator
@pagy, @records = pagy(:keyset, Product.some_scope, **options) # :keyset paginator
@pagy, @records = pagy(...)Read the Choose Right guide to pick the right paginators for your app
=== {{ include "snippets/mini-step" step: "3" }} Render navigation tags and other helpers with the @pagy instance methods:
<%# Render navigation bar helpers with various types and styles %>
<%== @pagy.series_nav %>
<%== @pagy.series_nav_js(:bootstrap) %>
<%== @pagy.input_nav_js(:bulma) %>
<%== @pagy.info_tag %>See all the available @pagy helpers
===
Guides Safety (`docs/guides/safety.md`)
label: Safety icon: shield order: 98
:icon-shield: Safety
!!!success
Pagy handles the input of its own URL params safely, and assumes that all the configuration, options and arguments you set in your code are safe to use verbatim in its helpers.
!!!
!!!warning WARNING!
If you use any other raw end-user input in your Pagy configuration, options, or arguments, you must sanitize or escape it first in your own code.
!!!
Guides Upgrade Guide (`docs/guides/upgrade-guide.md`)
label: Upgrade to 43
icon: check-circle
order: 70
nav:
badge:
icon: arrow-right
text: "43"
variant: info
:icon-check-circle: Upgrade to 43
Pagy version 43 is a complete redesign of the legacy code. Its improvements make pagination a lot simpler and more powerful, but require a quite different way to use it.
!!!success Follow this guide to upgrade your app in just a few minutes.
Cherry-pick only what applies to your app: you can safely skip all the rest.
!!!
Steps
Replace the
pagy.rbconfig file...
- Rename your
pagy.rbinitializer aspagy-old.rb. - Add the new pagy.rb initializer in its place.
- Cut/remove the
Pagy::DEFAULT[...]lines frompagy-old.rband paste/add them topagy.rb. - Replace all the
Pagy::DEFAULT[...]entries withPagy::OPTIONS[...]inpagy.rb.
In the next steps we will use the pagy-old.rb as the blueprint to guide most of the changes, and we will edit the new pagy.rb as needed.
Remove your used extras...
The new version doesn't use the extras anymore. They got integrated into the core code, and a few have been discontinued.
- Search for any active
require 'pagy/extras/*'in thepagy-old.rbfile... - When you find one, follow the specific section below to upgrade your code.
- As you proceed, remove each entry from the
pagy-old.rb.
==- Extras
:::
==- array
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_array(...) |
pagy(:offset,...) |
==- arel
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_arel(...) |
pagy(:offset, count_over: true, ...) |
==- pagy
- All the old helpers are now
@pagyinstance methods with more explicit names.
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_nav_js(@pagy, ...) |
@pagy.series_nav_js(...) |
pagy_combo_nav_js(@pagy, ...) |
@pagy.input_nav_js(...) |
pagy_limit_selector_js(@pagy, ...) |
@pagy.limit_tag_js(...) |
pagy_prev_url(@pagy, ...) |
@pagy.page_url(:previous, ...) |
pagy_next_url(@pagy, ...) |
@pagy.page_url(:next, ...) |
pagy_prev_a(@pagy, ...) |
@pagy.previous_tag(...) |
pagy_next_a(@pagy, ...) |
@pagy.next_tag(...) |
pagy_prev_link(@pagy, ...) |
discontinued: implement manually |
pagy_next_link(@pagy, ...) |
discontinued: implement manually |
size: ...``Pagy::OPTIONS[:size] = ... |
slots: ...``Pagy::OPTIONS[:slots] = ... |
ends: false``Pagy::OPTIONS[:ends] = false |
compact: true``Pagy::OPTIONS[:compact] = true |
==- bootstrap
- All the old helpers are now
@pagyinstance methods with more explicit names.
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_bootstrap_nav(@pagy, ...) |
@pagy.series_nav(:bootstrap, ...) |
pagy_bootstrap_nav_js(@pagy, ...) |
@pagy.series_nav_js(:bootstrap, ...) |
pagy_bootstrap_combo_nav_js(@pagy, ...) |
@pagy.input_nav_js(:bootstrap, ...) |
size: ...``Pagy::OPTIONS[:size] = ... |
slots: ...``Pagy::OPTIONS[:slots] = ... |
ends: false``Pagy::OPTIONS[:ends] = false |
compact: true``Pagy::OPTIONS[:compact] = true |
- FYI: The redundant
pagy-bootstrapclass has been removed from theinput_nav_jsbody.
==- bulma
- All the old helpers are now
@pagyinstance methods with more explicit names.
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_bulma_nav(@pagy, ...) |
@pagy.series_nav(:bulma, ...) |
pagy_bulma_nav_js(@pagy, ...) |
@pagy.series_nav_js(:bulma, ...) |
pagy_bulma_combo_nav_js(@pagy, ...) |
@pagy.input_nav_js(:bulma, ...) |
size: ...``Pagy::OPTIONS[:size] = ... |
slots: ...``Pagy::OPTIONS[:slots] = ... |
ends: false``Pagy::OPTIONS[:ends] = false |
compact: true``Pagy::OPTIONS[:compact] = true |
- FYI: The
is-centeredCSS class has been removed. - FYI: The previous/next links have been moved to the beginning and end of the pagination.
==- countless
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_countless(...) |
pagy(:countless, ...) |
countless_minimal: true``Pagy::OPTIONS[:countless_minimal] = true |
headless: true``Pagy::OPTIONS[:headless] = true |
==- calendar
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_calendar(...) |
pagy(:calendar, ...) |
Pagy::Calendar::OutOfRangeError |
Pagy::RangeError |
flag: active: true |
disabled: false |
config: pagy: ... |
offset: ... |
- If your
pagy-old.rbfile contains any localization configuration, then uncomment and customize the following line in thepagy.rbinitializer:Pagy::Calendar.localize_with_rails_i18n_gem(*your_locales).- Note: In non-Rails applications, calendar localization requires adding
rails-i18nto your Gemfile.
- Note: In non-Rails applications, calendar localization requires adding
- Remove any existing
Pagy::Calendar::*::DEFAULT. Pass the options to each unit when you paginate.
==- elasticsearch_rails
- Active and passive modes are now handled by the same
pagymethod:
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_elasticsearch_rails(...) |
pagy(:elasticsearch_rails, ...) |
Pagy.new_from_elasticsearch_rails(...) |
pagy(:elasticsearch_rails, ...) |
elasticsearch_rails_search: ...``Pagy::OPTIONS[:elasticsearch_rails_search] = ... |
search_method: ...``Pagy::OPTIONS[:search_method] = ... |
- Customization of the
pagy_searchmethod name has been discontinued:- Remove any existing
:elasticsearch_rails_pagy_searchvariable from your code. - Replace your custom method name with the standard
pagy_searchmethod.
- Remove any existing
==- meilisearch
- Active and passive modes are now handled by the same
pagymethod:
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_meilisearch(...) |
pagy(:meilisearch, ...) |
Pagy.new_from_meilisearch(...) |
pagy(:meilisearch, ...) |
meilisearch_search: ...``Pagy::OPTIONS[:meilisearch_search] = ... |
search_method: ...``Pagy::OPTIONS[:search_method] = ... |
- Customization of the
pagy_searchmethod name has been discontinued:- Remove any existing
:meilisearch_pagy_searchvariable from your code. - Replace your custom method name with the standard
pagy_searchmethod.
- Remove any existing
==- searchkick
- Active and passive modes are now handled by the same
pagymethod:
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_searchkick(...) |
pagy(:searchkick, ...) |
Pagy.new_from_searchkick(...) |
pagy(:searchkick, ...) |
searchkick_search: ...``Pagy::OPTIONS[:searchkick_search] = ... |
search_method: ...``Pagy::OPTIONS[:search_method] = ... |
- Customization of the
pagy_searchmethod name has been discontinued:- Remove any existing
:searchkick_pagy_searchvariable from your code. - Replace your custom method name with the standard
pagy_searchmethod.
- Remove any existing
==- headers
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_headers(...) |
@pagy.headers_hash(...) |
pagy_headers_merge |
response.headers.merge!(@pagy.headers_hash) |
headers: ...``Pagy::OPTIONS[:headers] = ... |
headers_map: ...``Pagy::OPTIONS[:headers_map] = ... |
- Notice that the
:limitheader default is now'page-limit'(it was'page-items').- Set
Pagy::OPTIONS[:headers_map] = { limit: 'page-items', ... }to preserve your current API, if it relies on the old default values.
- Set
==- jsonapi
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_jsonapi_links(@pagy, ...) |
@pagy.urls_hash(...) |
- Notice that the
nillinks are now removed as theJSON:APIspecification requires. - IMPORTANT: Enable the feature by explicitly setting the
jsonapi: trueoption (in the initializer orpagymethod).
==- keyset
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_keyset(...) |
pagy(:keyset, ...) |
pagy_keyset_first_url(@pagy, ...) |
@pagy.page_url(:first, ...) |
pagy_keyset_next_url(@pagy, ...) |
@pagy.page_url(:next, ...) |
filter_newest: ... |
override compose_predicate |
- Replace any existing
:jsonify_keyset_attributeswith:pre_serialize.- The lambda receives the same
keyset_attributesargument, but it must modify the specific values directly. The lambda's return value is ignored. For example:->(attrs) { attrs[:created_at] = attrs[:created_at].strftime('%F %T.%6N') }.
- The lambda receives the same
==- limit
{.compact}
| Search (old) | Replace with (new) |
|---|---|
limit_param: :... (symbol value) |
limit_key: '...' (string value) |
limit_extra: ... |
delete |
client_limit: ... |
delete |
- Enable the feature by setting
client_limit: allowed_max_limitoption (in the initializer orpagymethod).
==- metadata
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_metadata(@pagy, ...) |
@pagy.data_hash(...) |
metadata: ...``Pagy::OPTIONS[:metadata] = ... |
data_keys: ...``Pagy::OPTIONS[:data_keys] = ... |
data_key -> :scaffold_url |
:url_template |
==- overflow
- The
Pagy::OverflowErrorhas been replaced by thePagy::RangeError; however, it is no longer raised by default. - Pagy rescues the
Pagy::RangeErrorand serves an empty page by default.- Now, Pagy behaves the same as it did before when requiring the overflow extra and using its default settings.
- The legacy
pagy.overflow?is now thepagy.in_range?method, which checks/returns the opposite state/boolean. - The
overflow: :last_pagebehavior has been discontinued because it provides nearly no benefit:- Why is there little benefit in serving the last page?
- The navigation bar for an out-of-range request is rendered identically to that of the last page.
- The only difference is that there are no records/results to display.
- The "previous page" button points to the last page, so if users truly want to see the last page results (which they have likely already seen), they can simply click the link.
- Why is there little benefit in serving the last page?
- Summary for keeping the same behavior:
- The
:overflowoption is not used anymore. - If you did not use the extra (i.e., Pagy raised errors), set
raise_range_error: true. - If you used
overflow: :empty_pageor just required the overflow extra, simply remove it (this is now the default behavior). - If you used
overflow: :last_pageand still want this behavior despite the reasons above, see this How To Example.
- The
==- standalone
Replace the
:urlvariable with the:requesthash option. For example:rubyrequest: { base_url: 'http://www.example.com', path: '/path', params: { 'param1' => 1234 }, # The string-keyed params hash from the request cookie: 'xyz' } # The 'pagy' cookie, only for keynav
==- i18n
- If absolutely necessary, uncomment or add this line to your initializer:
Pagy.translate_with_the_slower_i18n_gem!.
==- gearbox (discontinued)
- Due to extensive overwriting for minimal benefit, you can safely remove this feature from your app without noticeable impact. Remove all
/gearbox/related code.
==- size (discontinued)
- Pagination bars similar to WillPaginate and Kaminari are not good for a lot of reasons. If still required, adapt the legacy file from a previous commit.
==- trim (discontinued)
- It was mostly useless and half-baked, causing many complications in both the Ruby and JavaScript code for no significant benefit.
- Use an appropriate approach to address your requirement, such as utilizing URL rewriting at the HTTP server level.
:::
Update the API...
==- Search and replace
{.compact}
| Search (old) | Replace with (new) |
|---|---|
include Pagy::Backend |
include Pagy::Method |
include Pagy::Frontend |
(remove: integrated) |
pagy_nav(@pagy, ...) |
@pagy.series_nav(...) |
Pagy.root. |
Pagy::ROOT. |
page_param: :... (symbol value) |
page_key: '...' (string value) |
pagy_info(@pagy, ...) |
@pagy.info_tag(...) |
@pagy_locale = ... |
Pagy::I18n.locale = ... |
@pagy.vars |
@pagy.options |
VariableError |
OptionError |
<error>.variable |
<error>.option |
fragment: '#...' (mandatory '#') |
fragment: '...' (optional '#') |
count_args: ... |
(remove: integrated) |
outset: ... |
(remove: discontinued) |
cycle: ... |
(remove: discontinued) |
==- Replace the :params variable...
Use the :querify option, which is a lambda that can modify the string-keyed params hash at will. It is a bit more verbose, but it's more powerful and low-level. It solves an incompatibility with the old high-level :params hash/lambda and improves performance. It is part of the URL Options group that gives you full and efficient control over the URL composition. For example:
# Old symbol-keyed, high-level hash variable
params: { a: 1, b: 2 }
# New string-keyed, low-level, direct modification of the params hash
querify: ->(p) { p.merge!('a' => 1, 'b' => 2) }
# It also allows things like:
querify: ->(p) { p.except!('not_useful').merge!('custom' => 'useful') }==- Replace the *prev* abbreviated naming
Use *previous* in all the options, accessors, methods, etc.
===
Finalize the upgrade...
==- JavaScript
If your pagy-old.rb contains any JavaScript setup, it should still work, so you can move it to the pagy.rb file; however, for apps with builders, consider using the new Pagy.sync and removing all the old entries from your JavaScript config files.
==- Stylesheets
The CSS for the default pagy helpers has new selectors and variables. See the new Stylesheets to interactively update your custom CSS.
!!!success CSS Frameworks
Supported CSS frameworks (like Bootstrap and Bulma) don't require any change.
!!!
==- Pagy::I18n and Locale Files
{{ include "snippets/mini-step" step: "1" }} If your pagy-old.rb contains the Pagy::I18n setup, and the setup includes some custom dictionary files, then uncomment and set up the relevant Pagy::I18n lookup section in the pagy.rb file. (See the I18n docs for details)
{{ include "snippets/mini-step" step: "2" }} Update your custom dictionary files (if any) to the new dictionary structure, or they won't work correctly.
{{ include "snippets/mini-step" step: "3" }} Remove all the I18n code from the pagy-old.rb. All the locales are autoloaded when your app uses them.
==- Overriding
- Overriding methods in controllers/helpers is either impossible or discouraged.
- The cleanest approach for local overriding is via Ruby refinements or the initializer for global override.
- Check the How To Override Pagy Methods.
- If your
pagy-old.rbcontains overridden methods, copy the methods over to thepagy.rbinitializer; however, consider that:- Internal Pagy protected methods have been extensively refactored, likely renamed, and occasionally removed.
- You should reconcile internal overrides by reviewing the updated Pagy codebase.
You may also want to check these internal renamings:
{.compact}
| Search (old) | Replace with (new) |
|---|---|
pagy_url_for(@pagy |
@pagy.page_url( |
pagy_anchor(pagy |
pagy.a_lambda( |
pagy_t |
Pagy::I18n.translate |
label_for |
page_label |
label |
page_label |
==- Delete the pagy-old.rb file
At this point, there should be no more code in the pagy-old.rb.
===
{{ include "snippets/ask-for-support" }}
!!!warning
Please report any issues with this guide by opening a New Docs Issue.
!!!
Resources ARIA (`docs/resources/ARIA.md`)
label: ARIA icon: accessibility order: 60
:icon-accessibility: ARIA Attributes
Pagy provides a consistent set of ARIA-compliant attributes across all its helpers.
=== :icon-code: Nav helpers
Pagy provides a customizable aria-label for the root element of its helpers. It is usually a nav element. For the few helper styles that use a different root element, Pagy adds a role="navigation" attribute.
The default string for the aria-label of the root element is "Page" / "Pages" (translated and pluralized according to the total number of pages). This is arguably a better description of the navigation content than just "Pagination" (which is also difficult to translate in certain languages).
!!!danger Don't rely on ARIA default with multiple nav elements!
The nav elements are landmark roles and should be distinctly labeled.
!!!
!!!success Override the default :aria_labels for multiple navs with distinct values!
<%# Explicitly set the aria_label %>
<%== @pagy.series_nav(aria_label: 'Search result pages') %>!!!
==- :icon-link: Links
Links to the previous and next pages are rendered as "<" and ">" and are aria-labelled as translated "Previous" and "Next". You can customize both the link text and the aria-label by editing the pagy.previous, pagy.next, pagy.aria_label.previous, and pagy.aria_label.next values in the locale files.
Page links do not include an aria-label attribute because their text is a simple number (read by screen readers in the user's native language), making an explicit attribute redundant and inefficient.
Disabled links include the aria-disabled="true" attribute.
The current page is marked with the aria-current="page" attribute.
The role="link" attribute is applied to link elements in styles that lack an a tag or a href attribute.
The role="separator" is applied to the :gap.
===
Resources I18n (`docs/resources/i18n.md`)
label: I18n icon: globe order: 70
:icon-globe: Internationalization
Pagy handles string translation and pluralization using its own efficient i18n implementation.
!!!success
Apps using only the English language are supported out of the box without any I18n setup!
!!!
=== :icon-list-ordered: Setup
All Pagy strings are stored in dictionary files within its locales directory. These files adopt the same structure as the standard locale files for the i18n gem, allowing you to use them seamlessly with both engines.
Pick the I18n engine...
+++ Pagy::I18n
!!!success Recommended: ~18x faster and ~10x lighter
It works seamlessly even if the rest of your app works with the i18n gem.
!!!
Set the Pagy::I18n.locale for each request. For example:
before_action { Pagy::I18n.locale = params[:locale] }Notice: The default Pagy::I18n.locale is 'en'.
+++ I18n gem
!!!warning Slower
!!!
Switch the translation to the i18n gem. Pagy will only provide its dictionaries...
Pagy.translate_with_the_slower_i18n_gem!+++
==- :icon-book: Sample Dictionary
:::code source="/gem/locales/en.yml" title="en.yml":::
==- :icon-pencil: Customizing dictionaries
!!!warning IMPORTANT
If you use Pagy::I18n, name your custom dictionary as <locale>.yml.
!!!
Place your custom dictionaries in a directory and add its path to the I18n pathnames.
# Example for Rails:
Pagy::I18n.pathnames << Rails.root.join('config/locales/pagy')==- :icon-mortar-board: Contributing a Language
{{ include "snippets/ask-for-support" }}
Find the pluralization of your language...
{{ include "snippets/mini-step" step: "1" }} Locate the file of your locale in the list of pluralizations.
{{ include "snippets/mini-step" step: "2" }} Check the pluralization used in it.
{{ include "snippets/mini-step" step: "3" }} Confirm that Pagy has the same pluralization in the p11n directory.
||| If missing, you have two choices...
{{ include "snippets/mini-step" step: "easy" }} Create a new Feature Request asking for the addition of the pluralization for your locale.
{{ include "snippets/mini-step" step: "best" }} Create a new module for the pluralization (by adapting the same pluralization from the corresponding rails-i18n file) and include tests for it.
|||
Duplicate an existing dictionary...
{{ include "snippets/mini-step" step: "1" }} Pick a (similarly pluralized) dictionary in the gem/locales directory.
{{ include "snippets/mini-step" step: "2" }} Set the p11n entry to the right pluralization module name in the p11n directory.
{{ include "snippets/mini-step" step: "3" }} Provide the necessary plurals for aria_label.nav and item_name.
E.g., with the EastSlavic rule, provide the plurals for one, few, many, and other. With Other, provide only the other value, etc.
==- :icon-location: Localization
Localization is needed only by the calendar with non-en locales. See the calendar localization.
===
Resources Javascript (`docs/resources/javascript.md`)
label: JavaScript icon: file-code order: 80
:icon-file-code: JavaScript
!!!tip Add the oj gem to your Gemfile
It is not a requirement, but if present, the pagy JSON generation will be faster.
!!!
Setup
Pick a file...
+++ pagy.mjs
!!!success Good for apps with a minifier (Sprockets, builders, ...)
!!!
Make Pagy available in your JavaScript environment with...
import Pagy from "pagy.mjs"+++ pagy.min.js
!!!success Good for apps without a minifier (Propshaft, Importmaps, ...)
!!!
Make Pagy available in your JavaScript environment with...
<%= javascript_include_tag "pagy.min.js" ...%>
<script src="/path/to/pagy.min.js"></script>+++ pagy.js
!!!warning Use it only for debugging Pagy itself.
!!!
+++
{{ include "snippets/pick-a-conf" resource: ":javascript" resource_dir: "javascripts" remote_dir: "app/javascript" }}
Run the
Pagy.initon...
+++ "load" event
Pick which applies to your environment:
window.addEventListener("load", Pagy.init)
window.addEventListener("turbo:load", Pagy.init)
window.addEventListener("turbolinks:load", Pagy.init)
window.addEventListener("your-event", Pagy.init)+++ Stimulus connect
connect() {
Pagy.init(this.element);
}+++
Resources Stylesheets (`docs/resources/stylesheets.md`)
label: Stylesheets icon: file order: 90 image: ""
:icon-file: Stylesheets
Pagy includes a couple of CSS files and the tools to integrate your app's themes interactively.
!!!warning
You don't need any stylesheets if you use the pagy :bootstrap or :bulma helpers and styles.
!!!
Setup
Pick a file...
+++ pagy.css
!!!success Good for any app
!!!
==- CSS Source
:::code source="/gem/stylesheets/pagy.css" title="pagy.css":::
===
+++ pagy-tailwind.css
!!!warning Works only with apps using Tailwind
!!!
==- CSS Source
:::code source="/gem/stylesheets/pagy-tailwind.css" title="pagy-tailwind.css":::
===
+++
{{ include "snippets/pick-a-conf" resource: ":stylesheet" resource_dir: "stylesheets" remote_dir: "app/assets/stylesheets" }}
Customize the style...
Add this line to any template/layout <head> while developing:
<%== Pagy.dev_tools %>and adjust a few sliders to see the change in real time, right in your app, with the Pagy Wand. Then copy the CSS Override field and paste it into your own CSS.
:::raised
{width=300}
:::
==- :icon-key-asterisk: Selectors
To ensure a minimalistic valid output, complete with all the ARIA attributes, pagy outputs a single line with the minimum number of tags and attributes required to identify all the parts of the nav bars:
- The output of the
series_navandseries_nav_jshelpers is a series ofatags inside anavtag wrapper. - The disabled links are simply missing the
hrefattribute. - The
pagy series-navandpagy series-nav-jsclasses are assigned to thenavtag.
{{ include "snippets/run-app" app: "demo" }}
!!!tip
- You can target the
gapwith.pagy a[role="separator"] - You can target the previous and next links by using
.pagy a:first-childand.pagy a:last-childpseudo-classes. - Check the stylesheet comments to target other specific elements.
!!!
==- :icon-arrow-left: RTL
The pagy stylesheets automatically support Right-To-Left (RTL) languages. It respects the standard dir="rtl" attribute of the html tag or any parent element of the pagination.
===
Resources Urls (`docs/resources/urls.md`)
label: URLs icon: crosshairs order: 50
:icon-crosshairs: URLs
Pagy uses the current URL as the base to generate all the other page URLs. It retrieves it from the self.request when available, or from a :request option set to a Rack::Request or a simple Hash of :base_url, :path, :params (and a pagy :cookie value in case of Keynav pagination).
!!!primary
Pagy generates its specialized URLs ~20x faster than generic helpers like Rails' url_for. When possible, it just replaces the page value, without recalculating every part of a URL.
!!!
==- :icon-sliders: Options
These options give you full control over the URL composition for paginators and helpers:
:::
=== Consumed by Paginators
{{ include "options/paginator-url" }}
=== Consumed by Helpers
{{ include "options/helper-url" }}
:::
==- :icon-blocked: Params
!!!danger No framework params!
Pagy ignores the request.params because they are modified differently by different frameworks (Rails, Sinatra, etc.). It can only rely on the request.GET and request.POST methods, which are consistent across all Rack environments.
!!!
!!!danger No symbolic params!
The params that Pagy handles when composing its URLs are strictly string-keyed. That's how every gem/framework handles URLs, because it avoids the maintenance and performance overhead of converting symbols back and forth during URL composition.
!!!
==- :icon-download: GET
Serving paginated collections is a retrieval action that does not modify data; therefore, it should rely on GET requests. Since most applications follow this standard, Pagy parses and produces GET URLs out of the box.
==- :icon-upload: POST
If you must use POST to retrieve paginated collections, you should build your own POST forms/requests using the data provided by Pagy (e.g., via the data_hash or instance readers). However, Pagy parses and handles POST request parameters out of the box without additional configuration.
==- :icon-stop: Dynamic Segments
Routers (like the Rails router) allow defining parameters as part of the path (e.g., /items/:page)...
!!!danger
Pagy neither supports nor recommends dynamic path segments for the :page param.
!!!
Why?
The Cons are overwhelming.
:icon-thumbsup: Pros
{.list-icon}
- • Aesthetically cleaner URLs
- • Possibility to cache single pages at the edge (rarely necessary)
:icon-thumbsdown: Cons
{.list-icon}
- RFC 3986 Compliance
- • The
:pageparameter represents non-hierarchical data, which fits the definition of the query string component. - • It does not fit the definition of the path component, which represents hierarchical resources.
- • The
- Data Identification
- • A query string parameter is labeled data (
?page=2) identifiable without external context. - • A path segment (
/2) is unlabeled and relies on external routing logic to be handled, so it cannot be identified/used by agnostic code.
- • A query string parameter is labeled data (
- Performance
- • Dynamic segments are framework-specific routing concepts, not query params concepts.
- • Using framework code is not only non-agnostic, but significantly slower than pagy's generic query param handling.
- • Using it (or even just checking for it) would be an unnecessary burden for all the apps.
:::
==- OK, but what if I still want it in my own app?
!!!danger This file is provided as a courtesy configuration
It is not an officially supported or tested feature, as it bypasses the standard, high-performance Pagy URL generation logic.
Use it at your own risk and extra maintenance!
!!!
:::code source="/gem/apps/enable_rails_page_segment.rb" title="enable_rails_page_segment.rb":::
:::
Sandbox Console (`docs/sandbox/console.md`)
label: Console icon: terminal order: 90
:icon-terminal: Console
Allows you to interact with Pagy in an irb or pry environment without an app, providing a pre-configured stubbed environment for you.
You can use a few methods to create a simple collection paginated with the :offset paginator or to set the parameters as needed.
/* Detailed source-code truncated for AI context efficiency. */Sandbox Dev Tools (`docs/sandbox/dev_tools.md`)
label: DevTools icon: ai-model order: 80
:icon-ai-model: DevTools
Pagy offers a couple of tools to ease your development process.
You can activate them by adding this line in the <head> of your layout/page:
<%== Pagy.dev_tools %>:::content-center
{{ include "snippets/run-app" app: "demo" }}
:::
:icon-north-star: Pagy Wand
Adjust a few sliders to see the style changing in real time, right in your app...
- Control most of the visual aspects of pagy with a few presets and sliders.
- Copy/paste the generated "CSS Override" block into your stylesheet to persist it in your app.
- Click on the :icon-question: icon on the Wand for help.
:::raised
{width=450}
:::
Watch the Pagy Wand demo video:
:::raised
{width=450}
:::
:icon-sparkle: Pagy AI
Get answers to your specific questions, right in your app. Just type questions like: "What are the available paginators for DBs and search platforms?"
Sandbox Playground (`docs/sandbox/playground.md`)
label: Playground order: 100 icon: play
:icon-play: Playground
You can showcase, clone, and develop a few Pagy apps without needing to set anything up on your side!
$ pagy --help:icon-apps: Apps
We have a few single-file apps ready to run in your browser for various purposes. Most of them are used to run the E2E Test workflow.
==- :icon-pulse: Repro (interaction example) {#repro}
You can use this app as a starting point to try Pagy or reproduce issues to get support or file bug reports.
Clone the app
pagy clone reproYou should find the ./repro.ru cloned app file in the current directory. Feel free to rename or move it as you wish.
Develop it
This command runs your rackup app with a puma server.
pagy path/to/your-repro.ruOpen a browser and navigate to http://127.0.0.1:8000
==- :icon-ruby: Rails {#rails}
Use it to reproduce Rails-related Pagy issues.
pagy clone rails
pagy ./rails.ru==- :icon-search: Active Search {#active-search}
The interactive showcase for the :rails_active_search paginator, in active and passive modes.
pagy active_search==- :icon-eye: Demo {#demo}
The interactive showcase for all the pagy helpers and CSS styles.
pagy demo==- :icon-calendar: Calendar {#calendar}
The interactive showcase and reproduction tool for the :calendar paginator.
pagy calendar==- :icon-key: Keyset / Keynav {#keysets}
The interactive showcases/repros for the :keyset and :keynav_js paginators with ActiveRecord or Sequel sets, and for multiple independent :keynav_js instances (keynav+root_key):
pagy --help | grep key
keynav+root_key Showcase the Keynav pagination with independent instances
keynav Showcase the Keynav pagination (ActiveRecord example)
keyset Showcase the Keyset pagination (ActiveRecord example)
keyset_sequel Showcase the Keyset pagination (Sequel example)
pagy keynav
pagy keynav+root_key
pagy keyset
pagy keyset_sequel===
==- :icon-stop: Troubleshooting
All the pagy apps use bundler/inline, which should be able to install all the gems automatically at app startup.
Depending on your environment, you might get this message for some gem:
You have already activated GEMNAME v1, but your Gemfile requires GEMNAME v2.
Prepending `bundle exec` to your command may solve this.If bundle exec doesn't solve it, then try bundle update and gem cleanup. If you encounter another error after that:
... `find_spec_for_exe': can't find gem GEMNAME (>= 0.x) with executable EXEC (Gem::GemNotFoundException)then gem pristine GEMNAME should solve the problem.
===
Toolbox Helpers (`docs/toolbox/helpers.md`)
label: " ✳ Helpers" icon: mention order: 80
✳ Helpers
The @pagy instance provides all the helpers to use in your code.
Its class is determined by the paginator used, but you can safely ignore it.
!!!success The @pagy helpers are autoloaded only if used!
Unused code consumes no memory.
!!!
Toolbox Index.Yml (`docs/toolbox/index.yml`)
label: Toolbox
icon: package
order: 80
expanded: true
Toolbox Paginators (`docs/toolbox/paginators.md`)
label: " ✳ Paginators" icon: database order: 90
✳ Paginators
||| The pagy Method
The pagy method provides a common interface to all paginators. Include it where you are going to paginate a collection (usually in ApplicationController):
include Pagy::MethodYou can use it to paginate ANY collection, with ANY technique. For example:
@pagy, @records = pagy(:offset, collection, **options)
@pagy, @records = pagy(:keyset, set, **options)
@pagy, @records = pagy(...):offset,:keyset, etc. are symbols identifying the paginator. They implement the specific pagination.@pagyis the pagination instance. It provides all the instance helper methods to use in your code.@recordsare the records belonging to the requested page.
!!!info
The pagy method expects to find the rack request at self.request; however, you can also use pagy outside controllers or views, or pass your own :request option.
!!!
|||
Paginators
!!!tip Also read the Choose Right guide to ensure good performance and a smooth workflow.
!!!
The paginators are symbolic names of different pagination types/contexts (e.g., :offset, :keyset, :countless, etc.). You pass the name to the pagy method and pagy will internally instantiate and handle the appropriate paginator class.
!!!warning Avoid instantiating Pagy classes directly
Instantiate paginator classes only if the documentation explicitly suggests it.
!!!
!!!success Paginators and classes are autoloaded only if used!
Unused code consumes no memory.
!!!
==- :icon-stop: Troubleshooting
:::
==- Records may repeat in different pages or be missing
||| :icon-question: Unordered PostgreSQL collection
PostgreSQL collections must be ordered.
||| :icon-check-circle: Solutions
Chain something like .order(:id) to your collection. See the PostgreSQL Documentation
|||
:::
===
Includes Options Helper Url (`docs/_includes/options/helper-url.md`)
absolute: true
: Makes the URL absolute.
path: '/my_path'
: Overrides the request path in pagination URLs. Use the path only (not the absolute URL). (see Override the request path)
fragment: '...'
: URL fragment string.
querify: tweak
: Set it to a lambda to directly edit the passed string-keyed params hash itself. Its result is ignored.
tweak = ->(q) { q.except!('not_useful').merge!('custom' => 'useful') }Includes Options Helper (`docs/_includes/options/helper.md`)
anchor_string: 'data-turbo-frame="paginate"'
: Concatenate a verbatim raw string to the internal HTML of the anchor tags. It must contain properly formatted HTML attributes. It's not suitable for *_hash helpers.
{{ include "helper-url" }}
Includes Options Keyset (`docs/_includes/options/keyset.md`)
keyset: {...}
: Set it only to force the keyset hash of column/order pairs. (It is set automatically from the set order)
tuple_comparison: true
: Enable the tuple comparison e.g. (brand, id) > (:brand, :id). It works only with the same direction order, hence, it's ignored for mixed order. Check how your DB supports it (your keyset should include only NOT NULL columns).
pre_serialize: serialize
: Set it to a lambda that receives the keyset_attributes hash. Modify this hash directly to customize the serialization of specific values (e.g., to preserve Time object precision). The lambda's return value is ignored.
ruby serialize = lambda do |attributes| # Convert it to a string matching the stored value/format in SQLite DB attributes[:created_at] = attributes[:created_at].strftime('%F %T.%6N') end
{{ include "paginator" }}
Includes Options Navs (`docs/_includes/options/navs.md`)
id: 'my-nav'
: Set the id HTML attribute of the nav tag.
aria_label: 'My Label'
: Override the default pagy.aria_label.nav string of the aria-label attribute.See ARIA.
!!!danger
The nav elements are landmark roles and should be distinctly labeled!
!!!
!!!success
Override the default :aria_labels for multiple navs with distinct values!
<%# Explicitly set the aria_label %>
<%== @pagy.series_nav(aria_label: 'Search result pages') %>!!!
Includes Options Offset (`docs/_includes/options/offset.md`)
count_over: true
: Use this option with GROUP BY collections to calculate the total number of results using COUNT(*) OVER ().
raise_range_error: true
: Enable the Pagy::RangeError (which is otherwise rescued to an empty page by default).
{{ include "paginator" }}
Includes Options Paginator Url (`docs/_includes/options/paginator-url.md`)
jsonapi: true
: Enables JSON:API-compliant URLs with nested query string (e.g., ?page[number]=2&page[size]=100).
root_key: 'my_root'
: Set it to enable nested URLs with nested query string ?my_root[page]=2&my_root[limit]=100. Use it to handle multiple pagination objects in the same request.
page_key: 'my_page'
: Set it to change the key string used for the :page in URLs (default 'page').
limit_key: 'my_limit'
: Set it to change the key string used for the :limit in URLs (default 'limit').
Includes Options Paginator (`docs/_includes/options/paginator.md`)
limit: 10
: Specifies the number of items per page (default: 20).
client_limit: 200
: Allow the client to request a :limit up to :client_limit. A higher requested :limit is silently capped.
IMPORTANT If falsey or zero, the client cannot request any :limit.
page: force_page
: Set it only to force the current :page. (It is set automatically from the request param)
request: request || hash
: Pagy tries to find the Rack::Request at self.request. Set it only when it's not directly available in your code (e.g., Hanami, standalone app, test,...). For example:
ruby hash_request = { base_url: 'http://www.example.com', path: '/path', params: { 'param1' => 1234 }, # The string-keyed params hash from the request cookie: 'xyz' } # The 'pagy' cookie, only for keynav
{{ include "paginator-url" }}
Includes Options Series (`docs/_includes/options/series.md`)
slots: 9
: Override the default number of page :slots used for the navigation bar.
slots < 7fills the slots with contiguous pages around the current one.slots >= 7reserves the first and last slots for the first and last pages, separated from the rest by a...(:gap) slot when needed.- Prefer odd numbers of slots, which place the current page in the central slot.
compact: true
: Fill all the slots with contiguous pages, regardless of the number of slots.
Includes Snippets All But Keyset (`docs/_includes/snippets/all-but-keyset.md`)
!!!warning
{{ $.what | object.default "It" }} works with all paginators but :keyset.
!!!
Includes Snippets Ask For Support (`docs/_includes/snippets/ask-for-support.md`)
!!!question
Feel free to ask for further help via Pagy Support.
!!!
Includes Snippets Js Required (`docs/_includes/snippets/js-required.md`)
!button variant="info" icon="alert" size="s" corners="pill" text="JavaScript Setup Required!"
Includes Snippets Mini Step (`docs/_includes/snippets/mini-step.md`)
[!badge variant="info" size="s" corners="pill" text="{{ $.step }}"]
Includes Snippets Nav Styles (`docs/_includes/snippets/nav-styles.md`)
==- :icon-eye: Styles
:pagy/nil
: Pagy default style
:bootstrap
: Set classes: 'pagination pagination-sm any-class' style option to override the default 'pagination' class.
:bulma
: Set classes: 'pagination is-small any-class' style option to override the default 'pagination' classes.
Includes Snippets Offset Readers (`docs/_includes/snippets/offset-readers.md`)
offset
: The OFFSET used in the SQL query.
count
: The collection count.
from
: The position in the collection of the first item on the page. (Different Pagy classes may use different value types for it).
to
: The position in the collection of the last item on the page. (Different Pagy classes may use different value types for it).
last
: The last page.
pages
: The number of pages.
previous
: The previous page.
{{ include "paginator-readers" }}
Includes Snippets Paginator Readers (`docs/_includes/snippets/paginator-readers.md`)
next
: The next page.
page
: The current page.
limit
: The items per page.
in
: The actual items in the page.
records
: The fetched records for the current page.
options
: The hash of options of the object.
Includes Snippets Pick A Conf (`docs/_includes/snippets/pick-a-conf.md`)
Pick a configuration...
+++ Sync
!!!success Works with any app
!!!
The following statement will copy and keep synced your picked pagy* file in your own asset dir, so it will be processed like an asset of your app.
# Replace 'pagy*' with the file you picked
Pagy.sync({{ $.resource }}, Rails.root.join('{{ $.remote_dir }}'), 'pagy*') if Rails.env.development?==- Sync Task
If you prefer to sync manually or during an automation step, you can define your own task with a single line in the Rakefile, or any *.rake file:
# Pagy::SyncTask.new(resource, destination, *targets)
# Replace 'pagy*' with the file you picked
Pagy::SyncTask.new({{ $.resource }}, Rails.root.join('{{ $.remote_dir }}'), 'pagy*')and exec it with...
bundle exec rake pagy:sync{{ $.resource }}===
+++ Pipeline
!!!warning Works only with apps with an assets pipeline
!!!
Rails.application.config.assets.paths << Pagy::ROOT.join('{{ $.resource_dir }}')+++
Includes Snippets Run App (`docs/_includes/snippets/run-app.md`)
[!button corners="pill" variant="info" icon="play-24" text="Check it out with bundle exec pagy {{ $.app }}"](/sandbox/playground/#{{ $.anchor | object.default $.app }})
Toolbox Configuration Initializer (`docs/toolbox/configuration/initializer.md`)
label: Initializer icon: gear order: 80
:icon-gear: Initializer
Set your global options/defaults, or configure a few special features by editing the sample file below.
Ensure it loads by saving it into the Rails config/initializers directory, or by requiring it.
:::code source="/gem/config/pagy.rb" title="pagy.rb" language="ruby":::
Toolbox Configuration Options (`docs/toolbox/configuration/options.md`)
label: "Options" icon: sliders order: 100
:icon-sliders: Options Hierarchy
!!! This page documents the options hierarchy
The actual options are documented alongside the paginators and helpers that consume them.
!!!
Pagy implements a hierarchical options system working at three different levels, regardless of where the option gets consumed.
Levels
Global
- For example,
Pagy::OPTIONS[:limit] = 10set in the pagy.rb initializer. - The
Pagy::OPTIONSare inherited by all paginators and helpers. - Good practice: Call
Pagy::OPTIONS.freezeafter you set yourPagy::OPTIONS.
Paginator
- For example,
pagy(paginator, collection, **options). - The options passed to a paginator override the
Pagy::OPTIONSfor that instance. - They are also inherited by all the helpers used by the instance.
Helper
- For example,
@pagy.series_nav(**options). - The options passed to a helper override the options affecting its output.
- The options consumed upstream are not affected.
!!!success
- Keep options local
- For clarity, set options as close to where they're consumed as possible.
- Widen the scope when needed
- Use higher-level options when they conveniently affect broader scopes.
!!!
- Use higher-level options when they conveniently affect broader scopes.
Toolbox Helpers Anchor Tags (`docs/toolbox/helpers/anchor_tags.md`)
label: anchor_tags icon: code-square order: 140 image: ""
:icon-code-square: anchor_tags
:::raised
{width=73}
:::
:::content-center
{{ include "snippets/run-app" app: "demo" }}
:::
The previous_tag and next_tag return the enabled/disabled previous/next page anchor tag.
Useful to build minimalistic UIs that don't use nav bar links (e.g., :countless, :keyset paginators).
!!!successnext_tag works with all paginators
!!!
{{ include "snippets/all-but-keyset" what: "previous_tag" }}
=== :icon-tools: Usage
<%== @pagy.next_tag %>
<%== @pagy.previous_tag %>==- :icon-pin: Examples
require 'pagy/console'
=> true
>> puts @pagy.previous_tag
<a href="/path?example=123&page=2" rel="prev" aria-label="Previous"><</a>
=> nil
>> puts @pagy.next_tag
<a href="/path?example=123&page=4" rel="next" aria-label="Next">></a>
=> nil
>> puts @pagy.next_tag(text: 'Show Next', aria_label: 'my-next')
<a href="/path?example=123&page=4" rel="next" aria-label="my-next">Show Next</a>
=> nil==- :icon-sliders: Options
text: 'My Page'
: Override the default text (instead of looking up the pagy.previous/pagy.next entry in the dictionary).
aria_label: 'My Link'
: Override the default aria label (instead of looking up the pagy.aria_label.previous/pagy.aria_label.next entry in the dictionary).
{{ include "options/helper-url" }}
===
Toolbox Helpers Data Hash (`docs/toolbox/helpers/data_hash.md`)
label: data_hash icon: list-unordered order: 200
:icon-list-unordered: data_hash
data_hash plucks a hash of key-value pairs from the pagy object. It is useful for exporting pagination data to JavaScript frameworks like Vue.js, React.js, etc.
!!!success It works with all paginators
!!!
=== :icon-tools: Usage
@pagy, @records = pagy(:offset, collection, **options)
pagy_hash = @pagy.data_hash(data_keys: %i[page previous next previous_url next_url ...])
#=> { page: 3, previous: 2, next: 4, previous_url: ... }
render json: { data: @records, pagy: pagy_hash }==- :icon-pin: Examples
require 'pagy/console'
=> true
>> @pagy, @records = pagy(:offset, collection.new, page: 3)
=> [#<Pagy::Offset:0x00007f0802c9bd80 @request=#<Pagy::Request:0x00007f0802c858c8 @options={page: 3, request: #<Pagy::Request:0x00007f0802c858c8 ...>, client_limit: nil, limit: 20, count: 1000}, @base_url="http://www.example.com", @path="/path", @params={example: "123"}, @cookie=nil>, @options={limit: 20, limit_key: "limit", page_key: "page", page: 3, client_limit: nil, count: 1000}, @limit=20, @count=1000, @page=3, @last=50, @offset=40, @in_range=true, @from=41, @to=60, @in=20, @previous=2, @next=4>, [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]]
>> @pagy.data_hash(data_keys: %i[page previous next previous_url next_url])
=> {page: 3, previous: 2, next: 4, previous_url: "/path?example=123&page=2", next_url: "/path?example=123&page=4"}==- :icon-sliders: Options
data_keys: %i[...]
: For efficiency, always set the :data_keys option to restrict the output to ONLY the keys you need among the default list:
:count:current_url:first_url:from:in:last:last_url:limit:next:next_url:options:page:page_url(alias of:current_url):pages:previous:previous_url:series:to:url_template
Notice that you can also add other @pagy instance method names not included in the default list.
{{ include "options/helper-url" }}
==- :icon-tools: Usage of :url_template
This is a URL string containing the "P " page token as a placeholder for the page value.
For example: '/foo?page=P &bar=baz'.
Replace it with JavaScript to generate the actual page URLs:
pageUrl = url_template.replace('P ', '123')
// Result: '/foo?page=123&bar=baz'!!!warning You may not need it for simple cases!
Consider using the available :*_url data keys directly instead of relying on the :url_template.
!!!
===
Toolbox Helpers Headers Hash (`docs/toolbox/helpers/headers_hash.md`)
label: headers_hash icon: list-unordered order: 190
:icon-list-unordered: headers_hash
headers_hash generates the standard link header defined in RFC-8288, and adds 4 customizable headers useful for pagination, which you can merge into the response.headers.
It also adheres to the header casing introduced by rack version 3+ (see the rack-issue).
!!!success It works with all paginators
!!!
=== :icon-tools: Usage
# Any paginator will work
@pagy, @records = pagy(:offset, collection, **options)
# Merge the headers to the response
response.headers.merge!(@pagy.headers_hash)
render json: @records==- :icon-pin: Examples
require 'pagy/console'
=> true
>> @pagy, @records = pagy(:offset, collection.new, page: 3)
=> [#<Pagy::Offset:0x00007f0802c9a020 @request=#<Pagy::Request:0x00007f0802c84e28 @options={page: 3, request: #<Pagy::Request:0x00007f0802c84e28 ...>, client_limit: nil, limit: 20, count: 1000}, @base_url="http://www.example.com", @path="/path", @params={example: "123"}, @cookie=nil>, @options={limit: 20, limit_key: "limit", page_key: "page", page: 3, client_limit: nil, count: 1000}, @limit=20, @count=1000, @page=3, @last=50, @offset=40, @in_range=true, @from=41, @to=60, @in=20, @previous=2, @next=4>, [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]]
>> @pagy.headers_hash(absolute: true)
=> {"link" => "<http://www.example.com/path?example=123>; rel=\"first\", <http://www.example.com/path?example=123&page=2>; rel=\"prev\", <http://www.example.com/path?example=123&page=4>; rel=\"next\", <http://www.example.com/path?example=123&page=50>; rel=\"last\"", "current-page" => "3", "page-limit" => "20", "total-count" => "1000", "total-pages" => "50"}link <https://example.com:8080/foo?page=1>; rel="first", <https://example.com:8080/foo?page=2>; rel="prev",
<https://example.com:8080/foo?page=4>; rel="next", <https://example.com:8080/foo?page=50>; rel="last"
current-page 3
page-limit 20
total-pages 50
total-count 1000==- :icon-sliders: Options
headers_map: {...}
: Customize the headers:
```rb
default_map = { page: 'current-page',
limit: 'page-limit',
count: 'total-count',
pages: 'total-pages' }
# Optional customization
headers_map = { page: 'current-page',
limit: 'per-page',
pages: false, # disable the output
count: 'total' }
headers = @pagy.headers_hash(headers_map:)
# Note: You can also pass the `:headers_map` option to the paginator
```{{ include "options/helper-url" }}
==- :icon-light-bulb: Suggestions
Instead of explicitly merging the headers before each rendering...
If you use Rails, you can add an after_action to your application controller:
# It merges the headers if `@pagy` is initialized
after_action { response.headers.merge!(@pagy.headers_hash) if @pagy }
# Paginate normally in your action
@pagy, records = pagy(:offset, collection, **options)
render json: recordsIf your code is consistent across different actions...
You can encapsulate the statements in a custom pagy_render method in your application controller. For example:
def pagy_render(collection, **)
pagy, records = pagy(:offset, collection, **) # Any other paginator works as well
response.headers.merge!(pagy.headers_hash) # Adds pagination headers to the response
render json: records
end
# And use it in your standard actions:
pagy_render(collection, **options)===
Toolbox Helpers Info Tag (`docs/toolbox/helpers/info_tag.md`)
label: info_tag icon: code-square order: 120 image: ""
:icon-code-square: info_tag
:::raised
Displaying items 201-220 of 1000 in total
:::
:::content-center
{{ include "snippets/run-app" app: "demo" }}
:::
info_tag provides information about the content of the current pagination.
{{ include "snippets/all-but-keyset" }}
=== :icon-tools: Usage
<%== @pagy.info_tag(**options) %>==- :icon-pin: Examples
require 'pagy/console'
=> true
>> puts @pagy.info_tag # @pagy generated by countless/keynav doesn't have count
<span class="pagy info">Page 3 of 4</span>
=> nil
>> puts @pagy.info_tag
<span class="pagy info">Displaying items 41-60 of 1000 in total</span>
=> nil
>> puts @pagy.info_tag(id: 'the-info-tag', item_name: 'Products')
<span id="the-info-tag" class="pagy info">Displaying Products 41-60 of 1000 in total</span>
=> nil==- :icon-sliders: Options
id: 'my-info'
: The id HTML attribute of the span tag wrapping the info.
item_name: 'Products'
: The already pluralized string that will be used in place of the default item/items.
===
Toolbox Helpers Input Nav Js (`docs/toolbox/helpers/input_nav_js.md`)
label: input_nav_js icon: code order: 150 image: ""
:icon-code: input_nav_js{{ include "snippets/js-required" }}
:::raised
{width=204}
{width=178}
{width=201}
:::
:::content-center
{{ include "snippets/run-app" app: "demo" }}
:::
input_nav_js combines navigation and pagination info in a single compact element.
It is the fastest and lightest navigator, recommended when you care about efficiency and server load while still needing a UI (see Maximize performance).
{{ include "snippets/all-but-keyset" }}
=== :icon-tools: Usage
<%== @pagy.input_nav_js(**options) %> <%# default pagy style %>
<%== @pagy.input_nav_js(:bootstrap, **options) %>
<%== @pagy.input_nav_js(:bulma, **options) %>==- :icon-pin: Examples
/* Detailed source-code truncated for AI context efficiency. */{{ include "snippets/nav-styles" }}
==- :icon-sliders: Options
{{ include "options/navs" }}
{{ include "options/helper" }}
==- :icon-alert: Caveats
!!!danger Overriding *_js helpers is not recommended
The *_js helpers are tightly coupled with the JavaScript code, so any partial overriding on one side would be quite fragile and might break in future releases.
!!!
===
Toolbox Helpers Limit Tag Js (`docs/toolbox/helpers/limit_tag_js.md`)
label: limit_tag_js icon: code-square order: 130 image: ""
:icon-code-square: limit_tag_js{{ include "snippets/js-required" }}
:::raised
{width=202}
:::
:::content-center
{{ include "snippets/run-app" app: "demo" }}
:::
The limit_tag_js allows the user to select any arbitrary limit per page, up to the :client_limit option. It raises a Pagy::OptionError exception if the :client_limit is not truthy.
{{ include "snippets/all-but-keyset" }}
=== :icon-tools: Usage
<%== @pagy.limit_tag_js %>!!!success Pagy requests the right page number
After selecting a new limit, pagy reloads the page that roughly contains the same items shown before the reload.
!!!
==- :icon-pin: Examples
require 'pagy/console'
=> true
>> puts @pagy.limit_tag_js(client_limit: 100)
<span class="pagy limit-tag-js" data-pagy="WyJsdGoiLDQxLCIvcGF0aD9leGFtcGxlPTEyMyZwYWdlPVAgIiwiUCAiLCJMICJd"><label>Show <input name="limit" type="number" min="1" max="100" value="20" style="padding: 0; text-align: center; width: 3rem;"><a style="display: none;">#</a> items per page</label></span>
=> nil
>> puts @pagy.limit_tag_js(client_limit: 100, id: 'my-elector', item_name: 'Products')
<span id="my-elector" class="pagy limit-tag-js" data-pagy="WyJsdGoiLDQxLCIvcGF0aD9leGFtcGxlPTEyMyZwYWdlPVAgIiwiUCAiLCJMICJd"><label>Show <input name="limit" type="number" min="1" max="100" value="20" style="padding: 0; text-align: center; width: 3rem;"><a style="display: none;">#</a> Products per page</label></span>
=> nil==- :icon-sliders: Options
{{ include "options/helper-url" }}
==- :icon-alert: Caveats
!!!danger Overriding *_js helpers is not recommended
The *_js helpers are tightly coupled with the JavaScript code, so any partial overriding on one side would be quite fragile and might break in future releases.
!!!
===
Toolbox Helpers Page Url (`docs/toolbox/helpers/page_url.md`)
label: page_url icon: diff-renamed order: 175
:icon-diff-renamed: page_url
page_url returns the URL of any page of any instance. If the page is not available, it returns nil. It is useful to build minimalistic UIs that don't use nav bar links (e.g., :keyset paginator).
!!!success It works with all paginators
!!!
=== :icon-tools: Usage
@pagy.page_url(:next)
@pagy.page_url(23, page_key: 'custom_page')
...==- :icon-pin: Examples
require 'pagy/console'
=> true
>> @pagy, @records = pagy(:offset, collection.new, page: 3)
=> [#<Pagy::Offset:0x00007f0802af62c8 @request=#<Pagy::Request:0x00007f0802faf238 @options={page: 3, request: #<Pagy::Request:0x00007f0802faf238 ...>, client_limit: nil, limit: 20, count: 1000}, @base_url="http://www.example.com", @path="/path", @params={example: "123"}, @cookie=nil>, @options={limit: 20, limit_key: "limit", page_key: "page", page: 3, client_limit: nil, count: 1000}, @limit=20, @count=1000, @page=3, @last=50, @offset=40, @in_range=true, @from=41, @to=60, @in=20, @previous=2, @next=4>, [41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60]]
>> @pagy.page_url(:first)
=> "/path?example=123"
>> @pagy.page_url(:current)
=> "/path?example=123&page=3"
>> @pagy.page_url(:page) # alias of :current
=> "/path?example=123&page=3"
>> @pagy.page_url(:previous)
=> "/path?example=123&page=2"
>> @pagy.page_url(:next)
=> "/path?example=123&page=4"
>> @pagy.page_url(:last)
=> "/path?example=123&page=50"
>> @pagy.page_url(23, page_key: 'custom_page')
=> "/path?example=123&custom_page=23"
>> @pagy.page_url(23, absolute: true)
=> "http://www.example.com/path?example=123&page=23"
>> @pagy.page_url('long-page-id', absolute: true)
=> "http://www.example.com/path?example=123&page=long-page-id"==- :icon-sliders: Options
{{ include "options/helper-url" }}
===
Toolbox Helpers Series Nav (`docs/toolbox/helpers/series_nav.md`)
label: series_nav icon: code order: 170 image: ""
:icon-code: series_nav
:::raised
{width=288}
{width=248}
{width=304}
:::
:::content-center
{{ include "snippets/run-app" app: "demo" }}
:::
series_nav returns an HTML string containing pagination links, wrapped in a nav tag, ready to be used in your view.
{{ include "snippets/all-but-keyset" }}
=== :icon-tools: Usage
<%== @pagy.series_nav(**options) %> <%# default pagy style %>
<%== @pagy.series_nav(:bootstrap, **options) %>
<%== @pagy.series_nav(:bulma, **options) %>==- :icon-pin: Examples
/* Detailed source-code truncated for AI context efficiency. */{{ include "snippets/nav-styles" }}
==- :icon-sliders: Options
{{ include "options/series" }}
{{ include "options/navs" }}
{{ include "options/helper" }}
===
Toolbox Helpers Series Nav Js (`docs/toolbox/helpers/series_nav_js.md`)
label: series_nav_js icon: code order: 160 image: ""
:icon-code: series_nav_js{{ include "snippets/js-required" }}
+++Pagy
:::raised
{width=428}
:::
:::raised
{width=358}
:::
:::raised
{width=288}
:::
+++Bootstrap
:::raised
{width=428}
:::
:::raised
{width=358}
:::
:::raised
{width=288}
:::
+++Bulma
:::raised
{width=428}
:::
:::raised
{width=358}
:::
:::raised
{width=288}
:::
+++
:::content-center
{{ include "snippets/run-app" app: "demo" }}
:::
series_nav_js functions similarly to a series_nav, with the following added features:
- Optional responsiveness: dynamically fills the container width.
- Improves performance and optimizes resource usage (see Maximize performance).
{{ include "snippets/all-but-keyset" }}
=== :icon-tools: Usage
<%== @pagy.series_nav_js(**options) %> <%# default pagy style %>
<%== @pagy.series_nav_js(:bootstrap, **options) %>
<%== @pagy.series_nav_js(:bulma, **options) %>==- :icon-pin: Examples
/* Detailed source-code truncated for AI context efficiency. */{{ include "snippets/nav-styles" }}
==- :icon-sliders: Options
{{ include "options/series" }}
steps: { 0 => 5, 540 => 7, ... }
: Enable responsiveness. Assign a different number of :slots to different tag widths. It overrides the :slots option.
{{ include "options/navs" }}
{{ include "options/helper" }}
==- :icon-log: In Depth: :steps Option
Notice: when :steps is not set, the series_nav_js behaves almost like a series_nav: just faster.
Set it as a hash, where the keys are integers representing the widths in pixels, and the values are the :slots options to be applied for those widths.
For example:
{ 0 => 5, 540 => 7, 720 => 9 } means that from 0 to 540 pixels width, Pagy will use 5 slots, from 540 to 720 it will use 7 slots, and over 720 it will use 9 slots. (Read more about the :slots option in the Control the pagination bar section.)
!!!warning :steps must contain a 0 width
You can set any number of steps with any arbitrary width/slots. The only requirement is that the :steps hash must always contain the 0 width, or a Pagy::OptionError exception will be raised.
!!!
!!! Notice
The :steps option overrides the :slots option, while the :compact option applies to all the steps.
!!!
Setting the right steps
Setting the :steps can enhance responsiveness and ensure seamless transitions.
Consider these guidelines to achieve optimal results:
- Define discrete
:stepsusing width/slots pairs to control the pagination behavior. - Ensure the container's width accommodates all slots for a smooth transition as it resizes.
- Synchronize the pagy
:stepswith your container's discrete width changes, for consistent alignment. - Test responsiveness to confirm that assigned slots fit within the corresponding width for each step.
==- :icon-alert: Caveats
!!!warning HTML Fallback
If JavaScript is disabled in the client browser, this helper will not render anything. You should implement your own HTML fallback:
<noscript><%== @pagy.series_nav %></noscript>!!!
!!!warning Window Resizing
The series_nav_js elements are automatically re-rendered on window resize. If another function changes the size without causing a window resize, you need to explicitly re-render:
document.getElementById('my-pagy-nav-js').render();!!!
!!!danger Overriding *_js helpers is not recommended
The *_js helpers are tightly coupled with the JavaScript code, so any partial overriding on one side would be quite fragile and might break in future releases.
!!!
===
Toolbox Helpers Urls Hash (`docs/toolbox/helpers/urls_hash.md`)
label: urls_hash icon: list-unordered order: 180
:icon-list-unordered: urls_hash
urls_hash returns the :first, :previous, :next, :last non-nil URLs hash.
!!! JSON:API
With the jsonapi: true option, the :previous key becomes :prev, as the JSON:API specification requires.
!!!
!!!success It works with all paginators
!!!
=== :icon-tools: Usage
urls_hash = @pagy.urls_hash(**options)==- :icon-pin: Examples
/* Detailed source-code truncated for AI context efficiency. */==- :icon-sliders: Options
{{ include "options/helper-url" }}
===
Toolbox Paginators Calendar (`docs/toolbox/paginators/calendar.md`)
label: :calendar icon: calendar-24 order: 60 image: ""
:icon-calendar: :calendar
:::raised
{width=600}
:::
:::content-center
{{ include "snippets/run-app" app: "calendar" }}
:::
!!!warning ActiveSupport Required!
!!!
The :calendar is a TIME-RANGE paginator.
It enables cascade-filtering of the collection by time units (year, quarter, month, week, and day), followed by paginating the filtered collection using the :offset paginator.
!!!success Use this paginator when most pages contain results.
!!!
!!!warning Avoid using it for sparse datasets with numerous empty pages.
!!!
==- :icon-list-ordered: Setup
You must define a few simple methods in your app to configure and coordinate the objects created by the pagy method. See the following examples and comments (adapted from the Calendar app code).
# Note: All time values must be instances of ActiveSupport::TimeWithZone.
# REQUIRED: return the start and end limits of the collection as a 2-item array
def pagy_calendar_period(collection)
starting = collection.minimum(:created_at)
ending = collection.maximum(:created_at)
[starting.in_time_zone, ending.in_time_zone]
end
# REQUIRED: return the collection filtered by a time period
def pagy_calendar_filter(collection, from, to)
collection.where(created_at: from...to)
end
# OPTIONAL: return the array of counts per time unit
# If this method is defined, pagy will add an extra 'empty-page' CSS class
# to the links leading to empty pages, along with a title attribute containing information about each page link.
def pagy_calendar_counts(collection, unit, from, to)
# If collection is in order: :desc, add the reverse: true option to the next line
collection.group_by_period(unit, :created_at, range: from...to).count.values
end
# Example usage with default options.
def index
@calendar, @pagy, @records = pagy(:calendar, collection,
year: {},
month: {},
offset: {})
end<%== @calendar[:year].series_nav %>
<%== @calendar[:month].series_nav %>
<%== @pagy.info_tag %> for <%== @calendar[:month].page_label(@pagy.page, format: '%B %Y') %>.
... Render @records here ...
<%== @pagy.series_nav %>
<p>Showtime: <%= @calendar.showtime %></p>
<a href="<%= @calendar.url_at(Time.zone.now) %>">Go to now</a>=== :icon-tools: Usage
@calendar, @pagy, @records = pagy(:calendar, collection, year: {}, month: {}, offset: {})@calendaris a specialized hash that contains the pagy time unit objects (e.g.,:yearand:monthin this example).@pagyis the object representing the current page of records.@recordsis the paginated subset of the collection.- The
:yearand:monthparameters create time unit objects (default options are used in this example). :offsetis the offset instance that paginates the time-filtered collection.
==- :icon-gear: Configuration
The calendar configuration defines the calendar objects to be generated. These objects filter the collection by the selected time units.
You can include one or more unit levels using keys like :year, :quarter, :month, :week, or :day. Assign each key a hash of unit options. Use an empty hash for default values, e.g., year: {}, month: {}, ....
Unit Options
order: :desc
: Sets the order of the unit, either :asc or :desc. Make sure to order your collection accordingly.
format: '<strftime>'
: Change the label format for the unit links.
!!!warning Option Restrictions
Do not try to set :page, :page_key, :querify, or :period options manually. These options are handled automatically, so setting them explicitly has no effect.
The Pagy::OPTIONS are not applied to the unit objects.
!!!
The `disabled` flag
The calendar is enabled by default. However, you can include an optional :disabled boolean flag in the configuration hash to disable the calendar bars. This is useful to display the regular pages of the collection without any filtering or calendar UI.
Offset Object
- The :offset paginator object is always used, regardless of the
:disabledflag value. If omitted, a default one will be created. - It is not subject to the Option Restrictions mentioned above.
==- :icon-hash: Methods
@calendar.url_at(time, **options)
: Returns a URL complete with all parameters for the pages in each filter bar that includes the given time. For example:
@calendar.url_at(Time.zone.now) generates the filter bar URLs pointing to today.
If time is outside the pagination range, it raises a Pagy::RangeError; however, you can pass the fit_time: true option to avoid the error and get the URL to the page closest to the passed time argument (first or last page).
@calendar.showtime
: Displays the time of the smallest time unit currently visible on the calendar.
==- :icon-location: Localization
Pagy provides the calendar localization only for en locales. For other locales, pagy requires the rails-i18n gem.
Pass the locales that your app uses to the method localize_with_rails_i18n_gem in the pagy.rb initializer:
Pagy::Calendar.localize_with_rails_i18n_gem(*your_locales)==- :icon-alert: Caveats
!!!warning Calendar pages with no records are visible and accessible.
You may want to display a message when @records.empty?.
!!!
===
Toolbox Paginators Countish (`docs/toolbox/paginators/countish.md`)
label: :countish icon: move-to-end-24 order: 95
:icon-move-to-end: :countish
:countish is an OFFSET paginator that memoizes the result of the COUNT query in the page links, running it only once per collection (instead of once per page), optionally recounting it when it's stale.
It fully supports all the helpers and navigators.
=== :icon-tools: Usage
# count only once and memoize for all pages
@pagy, @records = pagy(:countish, collection, **options)
# count once, memoize, and recount when the memoized count is older than ttl
@pagy, @records = pagy(:countish, collection, ttl: 300, **options)@pagyis the pagination instance. It provides the readers and the helpers to use in your code.@recordsrepresents the paginated collection of records for the page (lazy-loaded records).:ttlis the Time To Live of the memoized count. Counts only once ifnil.
==- :icon-sliders: Options
ttl: 180
: A positive number of seconds enables recounting. Setting it to nil (falsey) queries the DB for the COUNT only once, and reuses it for all the other pages served.
!!!warning Recounting/TTL
- Recounting gets the user more precise info and minimizes the page differences with lengthy page-browsing and abundant DB insertions/deletions.
- It does not fix the OFFSET-intrinsic data-shift of records on active DB insertions/deletions.
!!!
{{ include "options/offset" }}
==- :icon-mention: Readers
{{ include "snippets/offset-readers" }}
===
Toolbox Paginators Countless (`docs/toolbox/paginators/countless.md`)
label: :countless icon: move-to-end-24 order: 90
:icon-move-to-end: :countless
:countless is an OFFSET paginator that avoids the COUNT query, cutting the number of queries per page in half. UI helpers work with some limitations (see Caveat).
!!!warning Consider using the :keynav_js paginator when possible!
The :keynav_js offers identical UI features but uses the faster KEYSET pagination.
!!!
=== :icon-tools: Usage
@pagy, @records = pagy(:countless, collection, **options)@pagyis the pagination instance. It provides the readers and the helpers to use in your code.@recordsrepresents the eager-loadedArrayof records for the page.
==- :icon-sliders: Options
headless: true
: Use this option when UI is unnecessary (e.g., for infinite scrolling) and/or to skip eager loading. In this scenario:
@pagyis incompatible with any helpers.@recordsbehaves like a standard collection.- The collection ends when
@records.size < @pagy.limit.
{{ include "options/offset" }}
==- :icon-mention: Readers
{{ include "snippets/offset-readers" }}
==- :icon-alert: Caveat
!!!warning Nav bar links beyond the highest visited page are not known/displayed.
!!!
===
Toolbox Paginators Elasticsearch Rails (`docs/toolbox/paginators/elasticsearch_rails.md`)
label: :elasticsearch_rails icon: search order: 50
:icon-search: :elasticsearch_rails
:elasticsearch_rails is a SEARCH paginator for ElasticsearchRails search results.
=== :icon-tools: Usage
+++ Active mode
!!!success Pagy searches and paginates
You use the pagy_search method in place of the search method.
!!!
extend Pagy::Search# Get the collection in one of the following ways
search = Article.pagy_search(params[:q])
search = Article.pagy_search(params[:q]).records
search = Article.pagy_search(params[:q]).results
# Paginate it
@pagy, @response = pagy(:elasticsearch_rails, search, **options)
# IMPORTANT: If the Elasticsearch max_result_window is != 10_000, sync it with pagy
@pagy, @response = pagy(:elasticsearch_rails, search, max_result_window: 1_000, ...)+++ Passive mode
!!!success You search and paginate
Pagy creates its object out of your result.
!!!
# Standard response (already paginated)
@response = Article.search(params[:q], from: 0, size: 10, ...)
# Get the pagy object out of it
@pagy = pagy(:elasticsearch_rails, @response, **options)
# IMPORTANT: If the Elasticsearch max_result_window is != 10_000, sync it with pagy
@pagy = pagy(:elasticsearch_rails, @response, max_result_window: 1_000, ...)+++
!!!
Search paginators use the same positional technique as :offset paginators, with shared options and readers.
!!!
==- :icon-sliders: Options
max_result_window: 1_000
: Set it to the actual max_result_window applied by Elasticsearch, to get an accurate pagination count (default 10_000).
search_method: :my_search
: Customize the name of the ElasticsearchRails search method to use in active mode (default :search).
{{ include "options/paginator" }}
==- :icon-mention: Readers
{{ include "snippets/offset-readers" }}
===
Toolbox Paginators Keynav Js (`docs/toolbox/paginators/keynav_js.md`)
label: :keynav_js icon: key order: 70
:icon-key: :keynav_js{{ include "snippets/js-required" }}
:keynav_js is a fast KEYSET paginator that supports the UI. It's a Pagy-exclusive technique.
The Keynav pagination adds the numeric variables (@page, @last, @previous, @next, @in) to its instances, supporting their usage with the UI. It does so by transparently exchanging data with the client, which stores the state of the pagination.
If something goes wrong on the client side, it falls back to the :countless paginator seamlessly.
{{ include "snippets/run-app" app: "keynav" anchor: "keysets" }}
!!!warning This documentation extends the :keyset documentation.
It's easier to understand if you are familiar with the :keyset docs.
!!!
==- :icon-list-ordered: Setup
=== :icon-tools: Usage
@pagy, @records = pagy(:keynav_js, collection, **options)@pagyis the pagination instance. It provides the readers and the helpers to use in your code.@recordsis the eager-loadedArrayof the page records.
==- :icon-sliders: Options
{{ include "options/keyset" }}
==- :icon-mention: Readers
last
: The last page.
pages
: The number of pages.
previous
: The previous page
{{ include "snippets/keyset-readers" }}
==- :icon-log: In Depth: Cutoffs Filtering
Let's take a new look at the diagram of the keyset pagination explained in the Keyset documentation:
│ first page (10) >│ second page (10) >│ last page (9) >│
beginning of set >[· · · · · · · · · X]· · · · · · · · · Y]· · · · · · · · ·]< end of set
▲ ▲
cutoff-X cutoff-YLet's suppose that we navigate to page #3 (i.e., the last page), and we click on the link for page #2. We have stored the cutoff-X, so we can pull the 10 records after cutoff-X again as we did the first time... but are we sure that we would get the same results?
Let's suppose that the database just changed: 1 record was inserted before cutoff-X, and 2 records were deleted after cutoff-X...
│ page #1 (11) >│ page #2 (8) >│ page #3 (9) >│
beginning of set >[· · · · · · · · · · X]· · · · · · · Y]· · · · · · · · ·]< end of set
▲ ▲
cutoff-X cutoff-YAt this point, pulling 10 records from the cutoff-X would also get the first 2 records of page #3, and if you then navigate to page #3, you would pull the same 2 records again.
Indeed, not only have the results changed, but the cutoffs appear to have also shifted their absolute position in the set. In reality, the cutoffs have the same value as before, so they maintained their relative position in the set. However, now there is a different number of records falling into the same pages, which is totally consistent with the changes, but possibly unexpected. That is... if you have the mindset of OFFSET pagination, where the pages are split by number of records (absolute position) and not by their position relative to the records in the set.
!!!
The main goal of pagination is to split the results into manageable chunks and ensure it is as fast and accurate as possible, so the variation in the page size doesn't seem relevant to that. However, should it be relevant to you, you can always use the classic OFFSET pagination and accept its slowness and inaccuracy.
!!!
Pagy keynav doesn't use the LIMIT to pull the records of already visited pages. Instead, it replaces the LIMIT with the same filter used for the beginning of the page, and compounds it with the negated filter of the ending of the page.
For example, the filtering of the page could be logically described like:
- Page #1 `WHERE NOT AFTER CUTOFF-X` <- only ending filter
- Page #2 `WHERE AFTER CUTOFF-X AND NOT AFTER CUTOFF-Y` <- combined beginning + ending filter
- Page #3 `WHERE AFTER CUTOFF-Y LIMIT 10` <- regular beginning filter (no cutoff for last page)!!! Implementing page-rebalancing
When the number of records on a visited page has drastically changed, it would be helpful to mitigate the surprise effect on the user by:
- Automatically compacting the empty (or almost empty) visited pages.
- Automatically splitting the excessively grown visited pages.
!!!
==- :icon-alert: Caveat
!!!warning Nav bar links beyond the highest visited page are not known/displayed.
!!!
===
Toolbox Paginators Keyset (`docs/toolbox/paginators/keyset.md`)
label: :keyset icon: key order: 80
:icon-key: :keyset
:keyset is the fastest KEYSET paginator for ActiveRecord::Relation or Sequel::Dataset SQL ordered collections.
It uses a much faster pagination technique than OFFSET.
{{ include "snippets/run-app" app: "keyset" anchor: "keysets" }}
==- :icon-blocked: Constraints
!!!tip When a UI is needed, and using KEYSET Pagination is possible, use the :keynav_js paginator to overcome almost all these constraints.
!!!
!!!warning With any KEYSET pagination technique...
- You can only paginate from one page to the next: no jumping to arbitrary pages.
- The
setmust beuniquely ordered. Add the primary key (usually:id) as the last order column to be sure. - You should add the most suitable DB index for your ordering strategy, or there will be no performance gain.
!!!
!!!warning With Pagy :keyset...
You don't know the previous and the last page; you only know the first and next pages.
:icon-light-bulb: If you want to paginate backward, just call reverse_order on your set, and proceed forward.
!!!
==- :icon-list-ordered: Setup
Depending on your order requirements, here is how you set it up for maximum efficiency:
+++ No Order Requirement
Just order by :id. It's fast out of the box without any setup...
set = collection.order(:id)+++ Specific Order Requirement
Ensure that your set is
uniquely ordered
{{ include "snippets/mini-step" step: "Option 1" }} If the combination of the values of the ordered columns is certainly unique...
set = collection.order(:brand).order(:model){{ include "snippets/mini-step" step: "Option 2" }} If it's possibly not unique, just append a unique column to the order (e.g., your primary keys).
set = collection.order(:last_name).order(:first_name).order(:id)Ensure that your table has the appropriate index AND index type
{{ include "snippets/mini-step" step: "1" }} The index must include the exact same columns and ordering direction of your set.
{{ include "snippets/mini-step" step: "2" }} The index type must minimize the data scan (e.g., B-tree, B+ tree, ...).
+++
=== :icon-tools: Usage
@pagy, @records = pagy(:keyset, set, **options)@pagyis the pagination instance. It provides the readers and the helpers to use in your code.@recordsis the eager-loadedArrayof the page records.
<%== @pagy.next_tag(text: 'Next page >') %>==- :icon-sliders: Options
{{ include "options/keyset" }}
==- :icon-mention: Readers
{{ include "snippets/keyset-readers" }}
==- :icon-book: Glossary
There are a few peculiar aspects of the keyset pagination technique that you might not be familiar with. Here is a concise list:
offset pagination
: The technique to fetch each page by incrementing the offset from the collection start.It requires two queries per page (or only one if you use countless): it's slow toward the end of big tables.It can be used for a rich frontend: it's the classic pagy pagination.
keyset pagination
: The technique to fetch the next page starting after the latest fetched record in a uniquely ordered collection.It requires only one query per page (without OFFSET). If properly indexed, it's the fastest technique, regardless of the table size and position. Supports only infinite pagination, with no other frontend helpers.
keynav pagination
: The Pagy-exclusive technique to use keyset pagination, providing nearly complete UI support. The fastest technique with UI capabilities.
uniquely ordered
: The property of a set, when the concatenation of the values of the ordered columns is unique for each record. It is similar to a composite primary key for the ordered table, but dynamically based on the keyset columns.
set
: The uniquely ordered ActiveRecord::Relation or Sequel::Dataset collection to paginate.
keyset
: The hash of column/order pairs. Pagy extracts it from the order of the set.
keyset attributes
: The hash of attributes of the keyset columns of a record.
cutoff
: The value that identifies where the page ends, and the next one begins. It is the Base64 URL-safe encoded string of the serialized array of the keyset attribute values.
cutoffs
: The array of cutoffs of the known pagination state, used only by keynav to keep track of the visited pages during the navigation. They are cached in the sessionStorage of the client.
page
: The current page, i.e. the page of records beginning after the cutoff of the previous page. Also the :page option, which is set to the cutoff of the previous page.
next
: The next page, i.e. the page of records beginning after the cutoff. Also the cutoff value returned by the next method.
==- :icon-log: In Depth: Cutoffs
The cutoff of a page is the value that identifies where the page has ended, and the next one begins.
Let's consider an example of a simple set of 29 records, with an id column populated by character keys, and its order is: order(:id).
Assuming a LIMIT of 10, the "first page" will just include the first 10 records in the set: no cutoff value is known so far...
│ first page (10) >│ rest (19) >│
beginning of set >[· · · · · · · · · ·]· · · · · · · · · · · · · · · · · · ·]< end of setAt this point, it's the exact same first page pulled with OFFSET pagination, however, we don't want to use OFFSET to get the records after the first 10: that would be slow in a big table, so we need a way to identify the beginning of the next page without COUNTing the records (i.e., the whole point we want to avoid for performance).
So we read the id of the last one, which is the value X in our example... and that is the cutoff value of the first page. It can be described as: "the point up to the value X in the id column".
Notice that this is not like saying "up to the record X". It's important to understand that a cutoff refers just to a cutoff value of a column (or the values of multiple columns, in case of multi-column keysets).
Indeed, that very record could be deleted right after we read it, and our cutoff-X will still be the valid truth that we paginated the set up to the "X" value, cutting any further record off the page...
│ first page (10) >│ second page (10) >│ rest (9) >│
beginning of set >[· · · · · · · · · X]· · · · · · · · · ·]· · · · · · · · ·]< end of set
▲
cutoff-XFor getting the next page of records (i.e. the "second page") we pull the next 10 records AFTER the cutoff-X. Again, we read the id of the last one, which is Y: so we have our new cutoff-Y, which is the end of the current page, and the next will go AFTER it...
│ first page (10) >│ second page (10) >│ last page (9) >│
beginning of set >[· · · · · · · · · X]· · · · · · · · · Y]· · · · · · · · ·]< end of set
▲ ▲
cutoff-X cutoff-YWhen we pull the next page from the cutoff-Y, we find only the remaining 9 records, which means that it's the "last page", which naturally ends with the end of the set, so it doesn't have any cutoff value to separate it from further records.
!!! Keynotes
- A
cutoffidentifies a "cutoff value" for apagein theset. It is not a record, nor a reference to it. - Its value is extracted from the
keyset attributes valuesarray of the last record of thepage, converted to JSON, and encoded as a Base64 URL-safe string, for easy use in URLs.- The
:keysetpaginator embeds it in the request URL; the:keynav_jspaginator caches it on the clientsessionStorage.
- The
- All the
pages but the last end with thecutoff. - All the
pages but the first begin AFTER thecutoffof the previouspage.
!!!
==- :icon-stop: Troubleshooting
:::
==- {{ include "snippets/mini-step" step:"1" }} Records may repeat or be missing from successive pages
||| :icon-question: Order issue
Not unique combination...
Product.order(:name, :production_date)||| :icon-check-circle: Append the primary key to the order
The :id is usually the primary key...
Product.order(:name, :production_date, :id)|||
||| :icon-question: Encoding issue
The generic to_json method used to encode the page may lose some information when decoded.
||| :icon-check-circle: Solution
- Check the actual executed DB query and the actual stored value.
- Identify the column that has a format that doesn't match the keyset.
- Override the encoding with the :pre_serialize option.
|||
==- {{ include "snippets/mini-step" step:"2" }} The order is OK, but the DB is still slow
||| :icon-question: Index issue
The index has the wrong order, or it's the wrong type.
||| :icon-check-circle: Solutions
- Ensure that the index reflects exactly the column sequence and order of your keyset.
- Use a B-tree or B+ Tree index. Use SQL
EXPLAIN ANALYZEor a similar tool to confirm no table scan is performed. - With same-direction keysets, enabling the
:tuple_comparisonoption may help if your DB supports it.
|||
===
Toolbox Paginators Meilisearch (`docs/toolbox/paginators/meilisearch.md`)
label: :meilisearch icon: search order: 40
:icon-search: :meilisearch
:meilisearch is a SEARCH paginator for Meilisearch search results.
=== :icon-tools: Usage
+++ Active mode
!!!success Pagy searches and paginates
You use the pagy_search method in place of the ms_search method.
!!!
extend Pagy::Search
ActiveRecord_Relation.include Pagy::Search # Statically enable pagy_search on the model relations# Get the collection in one of the following ways
search = Article.pagy_search(params[:q])
search = Article.pagy_search(params[:q]).results
# Paginate it
@pagy, @response = pagy(:meilisearch, search, **options)+++ Passive mode
!!!success You search and paginate
Pagy creates its object out of your result.
!!!
# Standard results (already paginated)
@results = Article.ms_search(params[:q], hits_per_page: 10, page: 10, ...)
# Get the pagy object out of it
@pagy = pagy(:meilisearch, @results, **options)+++
!!!
Search paginators use the same positional technique as :offset paginators, with shared options and readers.
!!!
==- :icon-sliders: Options
search_method: :my_search
: Customize the name of the Meilisearch search method to use in active mode (default :ms_search).
{{ include "options/paginator" }}
==- :icon-mention: Readers
{{ include "snippets/offset-readers" }}
===
Toolbox Paginators Offset (`docs/toolbox/paginators/offset.md`)
label: :offset icon: move-to-end order: 100
:icon-move-to-end: :offset
:offset is a generic OFFSET paginator usable with ORM collections or regular Array objects.
It uses the complete OFFSET pagination technique, which triggers two SQL queries per request:
- a
COUNTquery to get the count; - an
OFFSET+LIMITquery to get the records.
It fully supports all the helpers and navigators.
!!!warning Consider using the :countish paginator when possible!
The :countish paginator offers identical UI features, but it's up to 2x faster.
!!!
=== :icon-tools: Usage
@pagy, @records = pagy(:offset, collection, **options)@pagyis the pagination instance. It provides the readers and the helpers to use in your code.@recordsrepresents the paginated collection of records for the page (lazy-loaded records).
==- :icon-sliders: Options
{{ include "options/offset" }}
==- :icon-mention: Readers
{{ include "snippets/offset-readers" }}
===
Toolbox Paginators Rails Active Search (`docs/toolbox/paginators/rails_active_search.md`)
label: :rails_active_search
icon: search
order: 35
nav:
badge:
text: "NEW"
variant: info
:icon-search: :rails_active_search
:rails_active_search is a SEARCH paginator for ActiveSearch (rails-active_search gem) search results.
{{ include "snippets/run-app" app: "active_search" anchor: "active-search" }}
=== :icon-tools: Usage
+++ Active mode
!!!success Pagy searches and paginates
You use the pagy_search method in place of the search method.
!!!
extend Pagy::Search# Get the collection (ActiveSearch keyword arguments, e.g., index: or scope:, are passed through)
search = Article.pagy_search(params[:q])
# Chain any ActiveSearch::Query method that returns a query (e.g., filter, sort, highlight)
search = Article.pagy_search(params[:q]).filter(status: 'published').sort(published_at: :desc)
# Paginate it: @results is the ActiveSearch::Results of the page
@pagy, @results = pagy(:rails_active_search, search, **options)!!!warning
Do not chain the pagination methods (limit, offset, page) nor the methods that end the chain (e.g., results, to_native_query).
!!!
+++ Passive mode
!!!success You search and paginate
Pagy creates its object out of your result.
!!!
# Standard results (already paginated)
@results = Article.search(params[:q]).limit(10).offset(20).results
# or
@results = Article.search(params[:q]).page(3, per_page: 10).results
# Get the pagy object out of it
@pagy = pagy(:rails_active_search, @results, **options)!!!warning
The :limit and :page are extracted from the results, so use a single Integer per_page with page: an Array of page sizes is not supported.
!!!
+++
!!!
Search paginators use the same positional technique as :offset paginators, with shared options and readers.
!!!
==- :icon-sliders: Options
search_method: :my_search
: Customize the name of the ActiveSearch search method to use in active mode (default :search).
{{ include "options/paginator" }}
==- :icon-mention: Readers
{{ include "snippets/offset-readers" }}
===
Toolbox Paginators Searchkick (`docs/toolbox/paginators/searchkick.md`)
label: :searchkick icon: search order: 30
:icon-search: :searchkick
:searchkick is a SEARCH paginator for Searchkick search results.
=== :icon-list-ordered: Setup
Searchkick.extend Pagy::Search=== :icon-tools: Usage
+++ Active mode
!!!success Pagy searches and paginates
You use the pagy_search method in place of the search method.
!!!
extend Pagy::Search# Single model
search = Article.pagy_search(params[:q])
# Multiple models
search = Searchkick.pagy_search(params[:q], models: [Article, Category])
# Paginate it
@pagy, @response = pagy(:searchkick, search, **options)
# IMPORTANT: If the Elasticsearch max_result_window is != 10_000, sync it with pagy
@pagy, @response = pagy(:searchkick, search, max_result_window: 1_000, ...)+++ Passive mode
!!!success You search and paginate
Pagy creates its object out of your result.
!!!
# Standard results (already paginated)
@results = Article.search(params[:q], page: 1, per_page: 10, ...)
# Get the pagy object out of it
@pagy = pagy(:searchkick, @results, **options)
# IMPORTANT: If the Elasticsearch max_result_window is != 10_000, sync it with pagy
@pagy = pagy(:searchkick, @results, max_result_window: 1_000, ...)+++
!!!
Search paginators use the same positional technique as :offset paginators, with shared options and readers.
!!!
==- :icon-sliders: Options
max_result_window: 1_000
: Set it to the actual max_result_window applied by Elasticsearch, to get an accurate pagination count (default 10_000).
search_method: :my_search
: Customize the name of the Searchkick search method to use in active mode (default :search).
{{ include "options/paginator" }}
==- :icon-mention: Readers
{{ include "snippets/offset-readers" }}
===
Toolbox Paginators Typesense Rails (`docs/toolbox/paginators/typesense_rails.md`)
label: :typesense_rails icon: search order: 20
:icon-search: :typesense_rails
:typesense_rails is a SEARCH paginator for Typesense::Rails search results.
=== :icon-list-ordered: Setup
Ensure Typesense.configuration[:pagination_backend] == nil.
=== :icon-tools: Usage
+++ Active mode
!!!success Pagy searches and paginates
You use the pagy_search method in place of the search method.
!!!
extend Pagy::Search# Get the collection
search = Article.pagy_search(params[:q], to_query)
# Paginate it
@pagy, @response = pagy(:typesense_rails, search, **options)+++ Passive mode
!!!success You search and paginate
Pagy creates its object out of your result.
!!!
# Standard results (already paginated)
@results = Article.search(params[:q], to_query, { per_page: 10, page: 10, ... })
# Get the pagy object out of it
@pagy = pagy(:typesense_rails, @results, **options)+++
!!!
Search paginators use the same positional technique as :offset paginators, with shared options and readers.
!!!
==- :icon-sliders: Options
search_method: :my_search
: Customize the name of the Typesense::Rails search method to use in active mode (default :search).
{{ include "options/paginator" }}
==- :icon-mention: Readers
{{ include "snippets/offset-readers" }}
===
--- METRICS ---
- Files Extracted: 65
- Estimated Token Budget: ~79744 tokens
- Canonical Reference: https://codewiki.google/github.com/ddnexus/pagy