I really like [will_paginate][1] for Ruby on Rails because it’s easy to setup and the intent of pagination is communicated well.

The only thing that bothers me is that it can be used with ActiveRecord only. My blog runs on Rails without ActiveRecord and all posts are kept in a git repository as simple markdown files. So I needed to write a wrapper that returns a WillPaginate::Collection and works on Arrays.

I came up with this:

# encoding: utf-8
require 'will_paginate'
require 'will_paginate/collection'

module WillPaginateArrays
  def paginate params
    params[:per_page] ||= 5
    params[:page] ||= 1

    return ::WillPaginate::Collection.create(
         params.fetch(:page),
         params.fetch(:per_page),
         self.length) do |pager|
       first_index = (pager.current_page - 1) * pager.per_page
       last_index = pager.current_page * pager.per_page

       pager.replace self[first_index...last_index]
    end
  end
end

The test_unit tests for the above snippet looks like this:

# encoding: utf-8
require 'will_paginate_arrays'
require 'test_helper'

class WillPaginateArraysTest < ActiveSupport::TestCase
  test "usage" do
    array = Array.new
    array.extend WillPaginateArrays
    assert array.respond_to?(:paginate)
  end

  test "#paginate follows per_page option" do
    array = (1..10).to_a
    array.extend WillPaginateArrays

    assert_equal 2, array.paginate(per_page: 2).length
    assert_equal [1, 2], array.paginate(per_page: 2)
  end

  test "#paginate follows page option" do
    array = (1..10).to_a
    array.extend WillPaginateArrays

    assert_equal (6..10).to_a, array.paginate(page: 2)
  end

  test "#paginate has total_pages" do
    array = (1..10).to_a
    array.extend WillPaginateArrays

    assert_equal 3, array.paginate(per_page: 4).total_pages
  end

  test "#paginate handles last page correctly" do
    array = (1..10).to_a
    array.extend WillPaginateArrays

    assert_equal [9, 10], array.paginate(per_page: 4, page: 3)
  end
end
``

As you can see usage is fairly easy:

  1. create a new array.
  2. extend the array with the `WillPaginateArrays` module
  3. call `#paginate` just like you normally would and use the `will_paginate` helper in your views.

Done!

[1]:https://github.com/mislav/will_paginate

comments powered by Disqus