When you’re diving into the world of handling large datasets in Ruby on Rails, you’ll quickly realize that pagination is your best friend. It not only makes the user experience smoother but also boosts the overall performance of your application. With a bunch of pagination gems out there, Pagy often snags the spotlight. Why? Well, because it’s blazing fast, super lightweight, and extremely flexible. If you’re ready to up your Rails game and paginate like a pro, this guide will walk you through making the most out of Pagy.
What’s So Special About Pagy?
Pagy is all about speed and efficiency. When dealing with big data, you need something that doesn’t hog resources. It outdoes other popular pagination gems like Kaminari and will_paginate in terms of both speed and memory efficiency. For instance, the nav_js
helpers provided by Pagy are about 40 times faster and 36 times lighter than what Kaminari offers. If you’re running a high-traffic website, Pagy is a very compelling choice.
Getting Pagy Up and Running
To kick things off, you need to install Pagy in your Rails application. It’s pretty straightforward. Here’s how you go about it:
First, add the Pagy gem to your Gemfile:
gem 'pagy', '~> 3.0.0'
Then, run the following command in your terminal:
bundle install
Next, you need to include Pagy’s modules in your application. A good place to do this is in your ApplicationController
:
class ApplicationController < ActionController::Base
include Pagy::Backend
end
This ensures that pagination is available across all controllers inheriting from ApplicationController
.
Tweaking Pagy to Fit Your Needs
Pagy is flexible and allows you to tweak various aspects of pagination via an initializer file. To get going, create an initializer:
# config/initializers/pagy.rb
Pagy::VARS[:items] = 10
This snippet sets the default number of items per page to 10. If you want to paginate a different number of items on a particular page, you can override this setting directly in your controller:
@pagy, @posts = pagy(Post.all.order(created_at: :desc), items: 20)
In this example, the @posts
collection is paginated to display 20 items per page.
How to Implement Pagination
To implement pagination in your controller actions, you’ll use the pagy
method. Here’s a quick example:
class PostsController < ApplicationController
def index
@pagy, @posts = pagy(Post.all.order(created_at: :desc), items: 10)
end
end
Now, in your view, add the following to render the pagination links:
<%= pagy_nav(@pagy) %>
This snippet will generate all the necessary pagination links directly in your view.
Making Pagination Look Good
Pagy lets you customize the pagination templates to match your application’s design. This means you can create custom HTML for your pagination links. Here’s how:
First, create a custom template:
<nav class="pagination">
<%= link_to "Previous", url_for(page: @pagy.prev), class: "prev" if @pagy.prev %>
<% @pagy.pages.each do |item| %>
<% if item == :gap %>
<span class="gap">…</span>
<% else %>
<%= link_to item, url_for(page: item), class: ("active" if item == @pagy.page) %>
<% end %>
<% end %>
<%= link_to "Next", url_for(page: @pagy.next), class: "next" if @pagy.next %>
</nav>
Save this file as _pagination.html.erb
in the app/views/pagy
directory. To use this custom template in your views:
<%= render 'pagy/pagination', pagy: @pagy %>
And just like that, you’ve got fully customized pagination links!
Handling Slow Count Queries
A big choke point in pagination is the count query, especially when you’re dealing with massive datasets. Pagy has some neat tricks to help you dodge this issue.
Caching the Count
You can cache the count of the collection to avoid hitting the database with a count query on every page load. Here’s a simple way to do this:
def pagy_get_count(collection, _vars)
cache_key = "pagy-#{collection.model.name}:#{collection.to_sql}"
Rails.cache.fetch(cache_key, expires_in: 20 * 60) do
collection.count(:all)
end
end
This will cache the result of the count query, which can be significantly faster.
Going Countless
Pagy’s countless
feature eliminates the need for a count query by just adding 1 to the limit condition, which is particularly helpful for UIs where minimalism or automatism is key:
@pagy, @posts = pagy(Post.all.order(created_at: :desc), count: false)
This method completely skips the count query, giving a substantial performance boost for large datasets.
Language Support
Got an international audience? Pagy has your back with built-in internationalization (i18n). You can localize your pagination links effortlessly.
Adding a Custom Locale
Say you need to add Greek localization. It starts with creating a locale file named pagy.el.yml
in your config/locales
directory:
el:
pagy:
nav:
prev: "‹ Προηγούμενη"
next: "Επόμενη ›"
gap: "…"
After setting your application to use the correct locale, Pagy fetches and uses these localized strings automatically for your pagination links.
Boosting Performance
Pagy isn’t just about good looks; it’s also about blazing fast performance.
Leveraging nav_js Helpers
The nav_js
helpers use client-side rendering, making it incredibly faster and lighter than server-side rendering:
<%= pagy_nav_js(@pagy) %>
This approach renders the pagination links using JavaScript, giving you a smoother experience.
Combining nav_js and Combo_nav_js
For apps that need both navigation links and total feedback:
<%= pagy_combo_nav_js(@pagy) %>
This method pairs well with the oj
gem for super-efficient front-end and back-end interactions.
Keyset Pagination
For humongous data, keyset pagination is your friend. Pagy supports this, and it’s generally more efficient than traditional offset-based pagination, especially when working with ActiveRecord::Relation
or Sequel::Dataset
.
Wrapping It Up
Pagy isn’t just another pagination gem; it’s a powerhouse designed for performance, efficiency, and flexibility. Whether you’re handling heaps of data or simply want a faster, lighter solution, Pagy fits right in. By following these steps, Pagy can be seamlessly integrated into your Rails application, making pagination smoother and more efficient, enhancing not just your app’s performance but also the overall user experience.