Customize Kaminari Pagination

Kaminari is a popular pagination gem for Rails application and provides a decent default template to get started.

In this tutorial, we will customize Kaminari template and allow to change dynamically the limit per page. We will use the following mock-up:

mockup layout Mockup layout

To get started, follow the steps below:

git clone -b get_started https://github.com/Maroo-b/kaminari_customization_tutorial.git

bundle install

rails db:setup

So we start by editing the app/views/kaminari/_paginator.html.erb partial:

<%= paginator.render do -%>
  <nav class="pagination">
    <%= first_page_tag unless current_page.first? %>
    <%= prev_page_tag unless current_page.first? %>
    <%= "#{current_page} of #{total_pages}" %>
    <% unless current_page.out_of_range? %>
      <%= next_page_tag unless current_page.last? %>
      <%= last_page_tag unless current_page.last? %>
    <% end %>
  </nav>
<% end -%>

Next, to display Bootstrap glyphicons for navigation we edit the locale file config/locales/en.yml

en:
  views:
    pagination:
      first: 'First'
      previous: '&lt;span class="glyphicon glyphicon-menu-left" aria-hidden="true"&gt;&lt;/span&gt;'
      next: '&lt;span class="glyphicon glyphicon-menu-right" aria-hidden="true"&gt;&lt;/span&gt;'
      last: 'Last'

Now it’s time to add dynamic page limits, I suggest to add the page sizes inside Kaminari config file like to avoid hardcoding values in the view.

config/initializers/kaminari_config.rb file

# frozen_string_literal: true
Kaminari.configure do |config|
  config.default_per_page = 10
  # config.max_per_page = nil
  # config.window = 4
  # config.outer_window = 0
  # config.left = 0
  # config.right = 0
  # config.page_method_name = :page
  # config.param_name = :page
  # config.params_on_first_page = false
end

PAGE_SIZES = [25, 50, 75]

And to display the pagination alongside filter links

app/views/articles/index.html.erb

<h3 class="text-center">Articles</h3>
<div class="clearfix">
  <div class="pull-left">
    <%= paginate items %>
  </div>
  <div class="pagination-filter pull-right">
    <span>Items per page</span>
    <ul>
      <% PAGE_SIZES.each do |size| %>
        <li><%= link_to size, url_for(per_page: size) %></li>
      <% end %>
    </ul>
  </div>
</div>
<%= render partial: 'item_table', locals: {items: @articles} %>

Next step is to edit the articles_controller file

def index
  if params[:per_page].present?
    @articles = Article.all.page(params[:page]).per(params[:per_page])
  else
    @articles = Article.all.page(params[:page])
  end
end

and to wrap it up we add a simple CSS:

.pagination-filter{
  margin: 20px 0;
  ul {
    display: inline-block;
    margin-left: -25px;
  }
  li {
    display: inline-block;
    list-style-type: none;
  }

  li a:after {
    content: ' |';
  }

  li:last-child a:after {
    content: '';
  }
}

The code implementation is available on the following Github repo.

Have fun and keep coding 🙂