Kaminari recipes

Dennis Ideler edited this page Feb 12, 2017 · 37 revisions

Here are tons of tips and howtos for Kaminari users!

☇ Don't forget to add an order scope

Kaminari internally uses AR's limit and offset. That means, uses limit and offset cause a SQL query. So, make sure to chain your pagination query with an order scope. For those of you who aren't sure what I mean, the following document will help you understand the point.


When using LIMIT, it is a good idea to use an ORDER BY clause that constrains the result rows into a unique order. Otherwise you will get an unpredictable subset of the query's rows — you might be asking for the tenth through twentieth rows, but tenth through twentieth in what ordering? You don't know what ordering unless you specify ORDER BY.



As Kaminari's paginating scope is just an ordinal AR scope, you can do that in quite natural way.


Of course default_scope works great with Kaminari for this purpose.

Rails 3:

class Book < ActiveRecord::Base
  default_scope order('published_at')

Rails 4:

class Book < ActiveRecord::Base
  default_scope ->{ order('published_at') }


☇ Specifying default per_page

Since version 0.9.6, you can specify default per_page value per each model using a declarative DSL method paginates_per.

class Book < ActiveRecord::Base
  paginates_per 50

I still wonder whether this is grammatically correct and makes sense as an English phrase. I would appreciate if anyone can suggest me a better declarative method name for this feature.

( I suggest default_page_size, or default_per_page, or pagination_page_size )

Also see the PageNumber gem.

☇ AR::Base#all is not a scope!

As AR::Base#all unfortunately returns an Array unlike DM, you can not do this:

User.all.page 2
#=> NoMethodError: undefined method `page' for #<Array:0x1017a9e80>

Let me tell you once again, AR::Base#all returns an Array (if you are using Rails 3, in Rails 4 AR::Base#all returns relation so you could use page and so on it). This is an FAQ, but not my fault!


☇ Dealing with labels for I18n and non-I18n apps

As described in README, the default labels for previous, ... and next are stored in the I18n yaml inside the engine, and rendered through I18n API. In fact this feature is not only for "international" apps but for everybody who wants to change the words on the labels. For example, if you want to change the prev_label to '<-', you don't have to override the whole partial template. Just add it to your locale file with en locale.

        previous: "<-"


☇ How to "autopagerize" my views?

I suppose you're all heavy addict of the life-changing autopagerize browser extension, right? So, here's a recipe that makes your website "autopagerizing".

  1. surround your repeating contents by a div with class="autopagerize_page_element"
  <div> or <table> or <whatever>
    - @books.each do |book|   or something
  1. place the paginate helper below

That's all. You'll realize your app starts working like Twitter! Hey, what a WEB 2.0!! It's paginating without clicking on any links! (so far as you're using "autopagirized" browser)


☇ POST links?

I never recommend you to do this. It's a horribly bad design. But you may sometimes encounter an unreasonable stupid situation that you are required to create POST links for paginating. Oh, dear. Then,

  1. pass :method => :post option to the paginator
= paginate @users, :method => :post
  1. override the Link sort of partials to pass the method value to link_to helper
= link_to page, url, :method => method

OK? Works?


☇ Overriding partials

You can override each tag's partial template by putting a file with proper name into app/views/kaminari/ directory. More explanation will be coming soon (or not soon).

☇ How do I paginate an Array?

Kaminari provides an Array wrapper class that adapts a generic Array object to the paginate view helper.


For more information on this, you may want to look at the "Paginating a generic Array object" section of https://github.com/kaminari/kaminari#paginating-a-generic-array-object

Keep in mind though that it is fairly easy to paginate an array in Ruby without using Kaminari.

arr = (1..100).to_a
page, per_page = 1, 10
arr[((page - 1) * per_page)...(page * per_page)] #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
page, per_page = 2, 10
arr[((page - 1) * per_page)...(page * per_page)] #=> [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

Who needs a special gem or plugin just for doing this?


☇ But I still want to paginate an Array by any means. How can I render the paginator?

OK, You're using Ruby. Something like this would do the work. Perhaps.

    @users = User.order(:created_at).page(params[:page]).all
    @users.instance_eval <<-EVAL
      def current_page
        #{params[:page] || 1}
      def num_pages
      def limit_value                                                                               

I'm not promising that this should work, but I'm just pointing out that you don't have to implement AbstractFactoryFactoryInterfaces to make it act like a paginatable collection.

If you want to be able to convert a Relation that has already been paginated into an Array, and still preserve all of the pagination data (so that you don't get an error in your view about missing method current_page, etc.), you can do this:

class UsersController
  def index
    @users_scope = User.order(:created_at).page(params[:page])
    @users = @users_scope.extend(Kaminari::PaginatableRelationToPaginatableArray).to_paginatable_array
module Kaminari
  module PaginatableRelationToPaginatableArray
    def to_paginatable_array
      relation = self
      PaginatableArray.new(self, total_count: relation.total_count).tap do |array|
        array.singleton_class.class_eval do
          define_method :current_page do
          define_method :total_pages do
          define_method :limit_value do
          define_method :offset_value do
          define_method :last_page? do

☇ Using Kaminari with InheritedResources

It's dead easy to add pagination to inherited_resources. First, make sure you list inherited_resources, kaminari and has_scope in your Gemfile.

Then, create a simple controller like this:

class ProductsController < InheritedResources::Base
  has_scope :page, :default => 1

And you're done! Look at the READMEs of the specific gems to learn more.

☇ Creating an "infinite scrolling"

Check out How To: Create Infinite Scrolling with jQuery.