Implementing Pagination in Rails with Kaminari
In this guide we will walk through how to integrate the Kaminari gem to add pagination to our Rails application.
Guide Tasks
  • Read Tutorial

Now that we have the majority of the design implemented for the application I want to integrate pagination to clean up our pages since right now 100% of the data is being shown on each page. Let's start by picking out a Ruby gem that will manage the pagination feature for us. There are two popular pagination libraries utilized by the Rails community:

  • Will Paginate
  • Kaminari

Even though Will Paginate seems to be the most popular option, I prefer Kaminari, I prefer its syntax and I really like how well it works for integrating AJAX based pagination, which is a feature we may or may not want to add to our application later on. I have already created an in depth Kaminari Guide that you can use for reference.

We're not going to create any specs for testing pagination since the gem itself is very well tested and it's a pretty straightforward integration. At some point later on we can add tests if we feel it's necessary, but for small features like this from trusted gems I'd rather simply get the feature implemented. Also, if we want to test pagination via AJAX it will require us to change the tests, so I'd rather not create busy work.

Installing Kaminari

Let's begin by getting the latest version of the gem from RubyGems.org and let's paste the gem code into our Gemfile:

# Gemfile

gem 'kaminari', '~> 0.17.0'

Configuring Pagination

After running bundle we can create our first pagination integration. Let's begin with our massive list of topics, to integrate pagination we'll need to make two code changes:

  1. Update the controller call
  2. Add the pagination to the view

Let's start by updating the controller and passing the Kaminari methods to the query:

# app/controllers/topics_controller.rb

  def index
    @topics = Topic.page(params[:page]).per(15)
  end

Here we're using the page method and passing in the parameters from the page as an argument. We're also using the optional per method, this allows us to dictate how many records will be shown on each page. Now let's update the view so that it render the pagination links:

<!-- app/views/topics/index.html.erb -->

<div class="container">
  <div class="row">
    <%= render @topics %>
  </div>

  <%= paginate @topics %>
</div>

Now let's startup the rails server and navigate to the topics/ path. It looks like the pagination is working, if you click from page to page you'll see that it's working:

large

If you've ever had to implement pagination in another framework or language you'll probably be shocked at how quickly we were able to knock this feature off the check list. It literally took three lines of code and our app now has pagination. So we have pagination, but it's quite ugly, so let's integrate a better looking set of links. Kaminari ships with a full set of styles that you can use, for DailySmarty we're going to use the standard Bootstrap 3 style elements. To update the styles simply run the command:

rails generate kaminari:views bootstrap3

Now if you startup the rails server again and refresh the page you'll see that our pagination links are looking much better.

large

It also created a full set of style files that we can customize if we so desire.

app/views/kaminari/_first_page.html.erb
app/views/kaminari/_gap.html.erb
app/views/kaminari/_last_page.html.erb
app/views/kaminari/_next_page.html.erb
app/views/kaminari/_page.html.erb
app/views/kaminari/_paginator.html.erb
app/views/kaminari/_prev_page.html.erb

Now all we have to do is populate the same method calls anywhere else that we want pagination. For right now I think the the Topic page is the only view that needs it since our homepage limits the count to 25 posts and we don't really want users paginating on the homepage. Let's update the controller first:

# app/controllers/topics/posts_controller.rb

  def index
    @posts = @topic.posts.page(params[:page]).per(10)
  end

Now let's update the view:

<!-- app/views/topics/posts/index.html.erb -->

<div class="container">

  <h1><%= @topic.title %></h1>

  <div class="row">
    <div class="col-xs-9 pull-left">
      <ul class="articles">
        <%= render 'shared/posts' %>
      </ul>
    </div>
  </div>

  <%= paginate @posts %>

  <%= link_to "New Post", new_post_path(topic_id: @topic.id) %>
</div>

Going to one of the Topic pages will show that everything is working now with pagination, nice work!

large

We have some cleanup to do in order to be able to move onto the next set of requirements and that's what we will do in the next guide.

Resources