Basically, a pagination gem needs to calculate a series of 10-20 sequencial integers (the page numbers) and loop through that series to produce one link per integer. That’s just a long string with a few numbers in it, and it’s a very simple task… unless someone build a whole complex world of thousands of objects around a simple series of integers :).
Pagy keeps pagination as straightforward as it could be: there are no “declarative DSL” to learn, no “global pollution” to avoid, no need for any special module or adapter. There are no nested modules, classes nor countless methods and many hundreds lines of code… all really difficult to justify for such a simple task.
Including all the features, validations, exceptions, etc., Pagy is just 3 small modules of just ~100 lines in total, easy to understand and use. Just take a look at the source: Pagy, Pagy::Backend, Pagy::Frontend .
Its size and simplicity is one of the reasons of its stunning performance.
Pagy is very specialized. It uses its own code to produce its own HTML, URLs, pluralization and interpolation. Unlike other gems it does not use any generic helpers such as rails helpers (
Those are perfect helpers but only if used in an application. Because they are generic they can get the job done in any situation, but exactly because they are generic, they are just the wrong tool to use in a pagination gem. Indeed they are inevitably A LOT slower and use A LOT more memory than specialized methods (or no method at all, like in case of HTML string interpolation extensively used by Pagy).
Paginating is not business logic: it has nothing to do with the data itself. It has to do with the way you decide to present the data… one page at the time, n items per page… That is indeed presentation logic, so the models are really not the place where to add that logic!
Every colletion knows already how to paginate itself: that’s what OFFSET and LIMIT in DBs are for! You decide the limit (the items per page) and Pagy (or yourself) can calculate the offset with simple arithmetic:
offset = items * (page - 1). That’s not rocket science! You don’t need to add a bunch of methods to your models just to get the page records!
Ignoring these simple rules has a lot of drawbacks for performance, memory, maintainance, complexity and usability, as you can confirm with the Gems Comparison page.
You don’t need a rails engine for a simple task like pagination: you just need a few lines of plain ruby to get it right, fast and light in any framework, not just rails.
Pagy provides the clean logic of pagination in one micro-class of less than 40 lines of code that creates a micro-object of less than 3k: it works perfectly, knowing absolutely nothing about your environment. (see the source)
You could even use it directly (without using any other Pagy code) in a small partial template that you could write in just 5 minutes and about 15 lines. There you could use the regular helpers provided by your framework and it would still work a few times faster than using other gems, even without using any Pagy template nor any other Pagy method.
If options and configuration are not enough, you have a few specialized extras, and if all that is still not enough, any other special customization is at most one step far from your own code. All the Pagy helpers are contained in 2 plain modules with no nesting. You include them in your code, so you can override any method right where you use it: no tricky gymnic required.
What could be easier?