Is Pagy the Secret Weapon for Blazing Fast Pagination in Rails?

Pagy: The Lightning-Quick Pagination Tool Your Rails App Needs

Is Pagy the Secret Weapon for Blazing Fast Pagination in Rails?

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">&hellip;</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.