simple_page

Adds simple but flexible pagination to ActiveRecord as well as the appropriate helpers to render page links.

Part of the core of this works was adapted from the github project paged_scopes.

Install the gem and you are ready to go. In your Gemfile:

gem 'simple_page'

In the Controllers

Use the simple_page helpers - this is only needed if you want to use the standard helpers and are not writing your own.

helper :simple_page

Modify your action to get the current page and set the page size:

def index
  @products = Product.where({})
  @products.page_size = 10
  @page = params[:page] || 1
  respond_with(@products)
end

Note the following: Instead of the standard Product.all - which returns an array - I have used Product.where({}) which returns a scope. The following line sets the pagination size, then we set a variable to select the current page (or page 1) depending on the parameters passed to the action.

Lastly we do a normal respond with the @products scope. Very little change to a normal controller method really.

Finding the page number for a known object

Something that I need to do from time to time. Especially when somebody direct links to an object and the pages are displayed within the “show” action

@product = Product.find(params[:id])
@products = Product.where({})
@products.page_size = 10
@page = @products.find_page_number(@product)

This is probably not the most wonderfully efficient thing to do, but it works. Feel free to contact me if you have a better method for implementing this than the one I’ve used.

In the Views

In a view where all of the products would normally be displayed, we now only want to display the products from the selected page. This can be achieved as follows:

<% @products.page(@page).each do |product| %>
...
<% end %>

Then at the bottom we put in page links:

<%= page_links(@products, @page) %>

Extras

As well as having a simple list of page numbers, there are four special or extra tags that can be used in the links: :first, :preview, :next, :last. The function of these should be reasonably self explanitory or you probably wouldn’t be here.

So the standard page_links function could be used like this:

<%= page_links(@products, @page, [:first, :previous, :next, :last]) %>

In the Helpers

Built in Helpers

These helpers should be fairly self explanitory. Better yet you can easily implement your own if you have formatting requirements. This way if you need pagination to appear differently in different parts of your applicaiton, it’s very straight forward to implement your own helpers.

def simple_page_marker(page)
  case page
      when :previous
          return "Previous"
      when :next
          return "Next"
      when :first
          return "First"
      when :last
          return "Last"
      else
          return page
  end
end

def page_links(collection, selected_page, extras = [ :previous, :next ], page_tag_helper = lambda {|page| simple_page_marker(page)})
   :ul, :class => "page_select" do
    collection.page_links_generator(selected_page, :inner => 2, :outer => 1, :extras => extras) do |tag, page_number, classes|
       :li, link_to(page_tag_helper.call(tag), params.merge(:page => page_number)), :class => (classes << :page).join(" ")
    end
  end
end