| The built-in pagination is being DEPRECATED. Look into the will_paginate plugin. |
The Pagination module 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.
The Pagination module 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.
Pagination is included automatically for all controllers.
PaginationHelper 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.
class PersonController < ApplicationController
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.
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.
def list
@person_pages = Paginator.new self, People.count, 10, params['page']
@person = People.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.
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_partial_collection.)
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,
<%= pagination_links(@person_pages) %>
will render a list of links. For a list of parameters, see the documentation for Page#pagination_links.
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 %>
<%= link_to(h('< Previous'), {:page => paginator.current.previous}) + " | " if paginator.current.previous %>
<%=pagination_links(paginator, :window_size => 4) %>
<%= " | " + link_to(h('Next >'), {:page => paginator.current.next}) if paginator.current.next %>
</div>
Then in your views, simply call
<%= render :partial => "partial/paginator", :locals => { :paginator => @person_pages } %>
wherever you want your pagination links to appear.
If you have search parameters that you need to include in the links to various pages you can use the following modified version of the above partial:
<div class="counter">
Displaying <%= paginator.current.first_item %>
- <%= paginator.current.last_item %>
of <%= paginator.item_count %>
<% search_params = params[:search].collect {|k,v| ["search[#{k.to_s}]", v]}.flatten.to_h %>
<%= link_to('« Previous', search_params.merge({:page => paginator.current.previous})) + " | " if paginator.current.previous %>
<%= pagination_links(paginator, :window_size => 4, :params => search_params) %>
<%= " | " + link_to('Next »', search_params.merge({:page => paginator.current.next})) if paginator.current.next %>
</div>
to_h doesn’t seem to be valid. Here’s an alternative:
<% search_params = Hash[*params[:search].collect {|k,v| ["search[#{k.to_s}]", v]}.flatten] %>
question: this code didn’t work for me, probably because of the use of params.
I replaced the search_params initialization by
<% search_params = request.parameters.delete_if { |key,value| [:action, :controller].include? key} %>
(wonder why request.query_parameters doesn’t exist.. It does but return a String)
Otherwise this is what I get:
undefined local variable or method `paginator' for #<#<Class:0xb74b31bc>:0xb74b316c>
[...]
vendor/rails/actionpack/lib/action_view/base.rb:316:in `compile_and_render_template'
vendor/rails/actionpack/lib/action_view/base.rb:292:in `render_template'
vendor/rails/actionpack/lib/action_view/base.rb:251:in `render_file'
vendor/rails/actionpack/lib/action_view/base.rb:266:in `render'
vendor/rails/actionpack/lib/action_view/partials.rb:59:in `render_partial'
Sometimes it’s nearly impossible to paginate a result set using the built-in :limit and :offset parameters of find(:all). Instead, you can fetch a complicated query and paginate the results afterward.
If you need to paginate a collection, add this method to your application.rb:
def paginate_collection(collection, options = {})
default_options = {:per_page => 10, :page => 1}
options = default_options.merge options
pages = Paginator.new self, collection.size, options[:per_page], options[:page]
first = pages.current.offset
last = [first + options[:per_page], collection.size].min
slice = collection[first...last]
return [pages, slice]
end
and call it from an action like this:
<div class="counter">
@pages, @users = paginate_collection User.find_custom_query, :page => params[:page]
</div>
—-
In paganation_links, is there any way to put the current page in a <span> element rather than just out there on it’s own?