“Ugh, I need to implement pagination, again.” Whether it’s pagination or something else, I’m never very fond of re-implementing or going on the search for yet another gem to take care of features that are trivially popular. Even as someone with a deep appreciation of Rails, this feels to me like a missing part. One more papercut, of sorts.
A May of WTFs thread, Active Pagination and Active Search, highlighted that need as well, with 600 views for now—an arguably popular topic overall.
My wish would be to write one line of code, and get sensible defaults and conventions, no decisions to make. So I went ahead and did it for my own need.
In my opinion, something like this should already be in Rails. Apparently it was in Rails 1, and it got removed for reasons which were probably sensible at the time.
I also saw that there were proposals in the works for an ActiveSearch module of some kind, but I thought I’d start smaller: just a simple limit-offset pagination.
Here it is:
# app/controllers/concerns/pagination.rb
module Pagination
extend ActiveSupport::Concern
def default_per_page
25
end
def page_no
params[:page]&.to_i || 1
end
def per_page
params[:per_page]&.to_i || default_per_page
end
def paginate_offset
(page_no-1)*per_page
end
def paginate
->(it){ it.limit(per_page).offset(paginate_offset) }
end
end
It makes all these helpful methods available in any controller you include it. If like me, you include it in ApplicationController:
class ApplicationController < EvenMoreAbstractController
include Pagination
end
It does not invoke itself everywhere, but you have access to it anywhere.
Usable like so:
(thanks to Ruby’s new-ish #then
method)
def index
records = Record.all
records.then(&paginate)
end
# which is a shortcut for
def index
records = Record.all
records.limit(per_page).offset(paginate_offset)
end
The param names I’ve chosen are :page
and :per_page
, both optional. eg:
GET /records
GET /records?page=3
-
GET /records?page=2&per_page=100
.
Done.
It is not perfect, I haven’t tested it extensively, but it feels to me like a simple, sensible defaults approach to pagination.
I would dream of a more polished version getting included in core, but I don’t have any expectations. I’m personally looking forward to never caring about this again, and gladly invite anyone along
Let’s care about more interesting problems, my friends!