Module: PaginationHelper

Included in:
ActionController::Base
Defined in:
app/helpers/pagination_helper.rb

Overview

Pagination Helper

Action Pack pagination for Active Record collections

Sam Stephenson <sstephenson at gmail dot com>

Pagination Helper aids in the process of paging large collections of Active Record objects. It offers macro-style automatic fetching of your model for multiple views, or explicit fetching for single actions. And if the magic isn’t flexible enough for your needs, you can create your own paginators with a minimal amount of code.

Unlike most helpers, Pagination Helper is available to all of Action Pack: it helps you query your models with Action Controller and render links in Action View.


Controller examples

Pagination Helper can handle as much or as little as you wish. In the controller, have it automatically query your model for pagination; or, if you prefer, create Paginator objects yourself.

Automatic pagination for every action in a controller

class PersonController < ApplicationController
  helper :pagination     
  model :person

  paginate :people, :order_by => 'last_name, first_name',
           :per_page => 20

  # ...
end

Each action in this controller now has access to a @people instance variable, which is an ordered collection of model objects for the current page (at most 20, sorted by last name and first name), and a @person_pages Paginator instance. The current page is determined by the @params['page'] variable.

Pagination for a single action

def list
  @person_pages, @people =
    paginate :people, :order_by => 'last_name, first_name'
end

Like the previous example, but explicitly creates @person_pages and @people for a single action, and uses the default of 10 items per page.

Custom/“classic” pagination

def list
  @person_pages = Paginator.new self, Person.count, 10, @params['page']
  @people = Person.find_all nil, 'last_name, first_name', 
            @person_pages.current.to_sql
end

Explicitly creates the paginator from the previous example and uses Paginator#to_sql to retrieve @people from the model.

View examples

Paginator Helper includes various methods to help you display pagination links in your views. (For information on displaying the paginated collections you retrieve in the controller, see the documentation for ActionView::Partials#render_collection_of_partials.)

Using Paginator#basic_html

Use the basic_html method to get a simple list of pages (always including the first and last page) with a window around the current page. In your view, using one of the controller examples above,

<%= @person_pages.basic_html(self) %>

will render a list of links. For a list of parameters, see the documentation for Page#basic_html.

Using a paginator partial

If you need more advanced control over pagination links and need to paginate multiple actions and controllers, consider using a shared paginator partial. For instance, _why suggests this partial, which you might place in app/views/partial/_paginator.rhtml:

<div class="counter">
  Displaying <%= paginator.current.first_item %>
  - <%= paginator.current.last_item %>
  of <%= paginator.item_count %> &nbsp; &nbsp;

  <%= link_to(h('< Previous'), paginator.current.previous.to_link) + 
      " | " if paginator.current.previous %>
  <%= paginator.basic_html(self, 4) %>
  <%= " | " + link_to(h('Next >'), paginator.current.next.to_link) if
      paginator.current.next %>
</div>

Then in your views, simply call

<%= render_partial "partial/paginator", @person_pages %>

wherever you want your pagination links to appear.


Thanks

Thanks to the following people for their contributions to Pagination Helper:

  • Marcel Molina Jr (noradio), who provided the idea for and original implementation of Paginator::Window, as well as endless mental support.

  • evl, who pointed out that Page#link_to should take and merge in a hash of additional parameters.

  • why the lucky stiff, who wrote a lovely article on the original Pagination Helper alongside the first implementation of Paginator#base_html, created Page#first_item and Page#last_item, and who provided inspiration for revising Pagination Helper to make it more “Rails-ish.”

  • xal, who saw the limitations of having only the macro-style paginate method and suggested the single-action version, and who also suggested the automatic inclusion into ActionController::Base.

  • jbd for feedback and debugging help.

  • ##rubyonrails on Freenode and the Rails mailing list.

Defined Under Namespace

Modules: ClassMethods Classes: Paginator

Constant Summary collapse

OPTIONS =

A hash holding options for controllers using macro-style pagination

Hash.new
DEFAULT_OPTIONS =

The default options for pagination

{
  :class_name => nil,
  :per_page   => 10,
  :parameter  => 'page',
  :conditions => nil,
  :order_by   => nil
}

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object

:nodoc:



140
141
142
143
# File 'app/helpers/pagination_helper.rb', line 140

def self.included(base) #:nodoc:
  super
  base.extend(ClassMethods)
end

.validate_options!(collection_id, options, in_action) ⇒ Object

:nodoc:

Raises:

  • (ActionController::ActionControllerError)


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'app/helpers/pagination_helper.rb', line 145

def self.validate_options!(collection_id, options, in_action) #:nodoc:
  options.merge!(DEFAULT_OPTIONS) {|key, old, new| old}

  valid_options = [:class_name, :per_page, 
                   :parameter, :conditions, :order_by]
  valid_options << :actions unless in_action
  
  unknown_option_keys = options.keys - valid_options
  raise ActionController::ActionControllerError,
        "Unknown options: #{unknown_option_keys.join(', ')}" unless
          unknown_option_keys.empty?

  options[:singular_name] = Inflector.singularize(collection_id.to_s)
  options[:class_name]  ||= Inflector.camelize(options[:singular_name])
end

Instance Method Details

#paginate(collection_id, options = {}) ⇒ Object

Returns a paginator and a collection of Active Record model instances for the paginator’s current page. This is designed to be used in a single action; to automatically paginate multiple actions, consider ClassMethods#paginate.

options are:

:class_name

the class name to use, if it can’t be inferred by singularizing the collection name.

:per_page

the maximum number of items to include in a single page. Defaults to 10.

:parameter

the CGI parameter from which the current page is determined. Defaults to ‘page’; i.e., the current page is specified by @params['page'].

:conditions

optional conditions passed to Model.find_all.

:order_by

optional order parameter passed to Model.find_all and Model.count.



177
178
179
180
# File 'app/helpers/pagination_helper.rb', line 177

def paginate(collection_id, options={})
  PaginationHelper.validate_options!(collection_id, options, true)
  paginator_and_collection_for(collection_id, options)
end