Rails 6 Database Record Pagination with Pagy
4th January 2021
Introduction
In this post I will outline a method the paginate database records in a Rails 6 app using the Pagy. gem. I will also cover the process of styling the paging navbar with bootstrap and font awesome icons.
Software
The following software was used in this post.
- Rails - 6.0.3.4
- Pagy - 3.5
- Bootstrap - 5.0.0-beta1
- Font Awesome (Free) - 5.15.1
Note
Pagy works with any rack app, therefore it is not tightly integrated into rails and is a bit more involved to setup than other paging gems.
Installation
Add the Pagy gem to your Gemfile
# Gemfile
gem 'pagy', '~> 3.5'
Then use bundle
to install the gem.
bundle install
Configuration
Include the Pagy backend into the app/controllers/application_controller.rb file.
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
include Pagy::Backend
end
Include the Pagy frontend into the app/helpers/application_helper.rb file.
# app/helpers/application_helper.rb
module ApplicationHelper
include Pagy::Frontend
end
Copy the pagy.rb configuration file from here to your config/initializers/ directory.
This file is where you apply some of the customization for Pagy and also enable any extras.
# config/initializers/pagy.rb
# Uncomment this line to enable bootstrap.
require 'pagy/extras/bootstrap'
# Return 25 records per page.
Pagy::VARS[:items] = 25
# Change to layout of the paginator nav bar.
Pagy::VARS[:size] = [1,2,2,1]
To use font awesome icons create a partial paginator.html.erb template file in the app/views/shared/ directory.
I used the template from here. Replacing the pagy_t calls with the Font Awesome icon HTML as strings I want to use.
Here is a quote from the docs:
This template is i18n-ready: if you don't use i18n, then you can replace the pagy_t calls with the actual strings ("‹ Prev", "Next ›", "…").
For Example:
From: pagy_t('pagy.nav.prev')
To: '<i class="fas fa-angle-left"></i>'
The complete template is below.
# app/views/shared/paginator.html.erb
<% link = pagy_link_proc(pagy, 'class="page-link"') %>
<nav aria-label="pager" class="pagy-bootstrap-nav" role="navigation">
<ul class="pagination">
<% if pagy.prev %>
<li class="page-item prev"><%== link.call(pagy.prev, '<i class="fas fa-angle-left"></i>', 'aria-label="previous"') %></li>
<% else %>
<li class="page-item prev disabled"><a href="#" class="page-link"><%== '<i class="fas fa-angle-left"></i>' %></a></li>
<% end -%>
<% pagy.series.each do |item| %>
<%# series example: [1, :gap, 7, 8, "9", 10, 11, :gap, 36] %>
<% if item.is_a?(Integer) %>
<li class="page-item"><%== link.call(item) %></li>
<% elsif item.is_a?(String) %>
<li class="page-item active"><%== link.call(item) %></li>
<% elsif item == :gap %>
<li class="page-item disabled gap"><a href="#" class="page-link"><%== '<i class="fas fa-ellipsis-h"></i>' %></a></li>
<% end %>
<% end %>
<% if pagy.next %>
<li class="page-item next"><%== link.call(pagy.next, '<i class="fas fa-angle-right"></i>', 'aria-label="next"') %></li>
<% else %>
<li class="page-item next disabled"><a href="#" class="page-link"><%== '<i class="fas fa-angle-right"></i>' %></a></li>
<% end %>
</ul>
</nav>
Now, Because we altered an initializer, restart your rails server to apply the changes.
Usage
In the controller actions that require paging. Wrap you queries in pagy calls.
# app/controllers/devices_controller.rb
class DevicesController < ApplicationController
def index
@pagy, @devices = pagy(Devices.all)
end
end
In the associated views render the paginator partial template created in a previous step.
# app/views/devices/index.html.erb
<%= render partial: "shared/paginator", locals: { pagy: @pagy }%>
And that's it. Behold the blazing fast beauty of Pagy. The result will look like the below.
Summary
In this post we added pagination to a Rails 6 app using the Pagy gem. We also used Bootstrap to style the paginator and used Font Awesome icons for the navigators and seperator.