Out of the box, will_paginate supports hooking in several ORMs to provide paginating finders based on their API. As of this writing, the supported libraries are:
Sequel
It’s easy to write your own adapter for anything that can load data with
explicit limit and offset settings. DataMapper adapter is a nice and compact example
of writing an adapter to bring the paginate method to DataMapper models.
ORDER BYIn most ORMs, :order parameter specifies columns for the
ORDER BY clause in SQL. It is important to have it, since
pagination only makes sense with ordered sets. Without the order clause,
databases aren’t required to do consistent ordering when performing
SELECT queries.
Ordering by a field for which many records share the same value (e.g. “status”) can still result in incorrect ordering with some databases (MS SQL and Postgres for instance). With these databases it’s recommend that you order by primary key as well. That is, instead of ordering by “status DESC”, use the alternative “status DESC, id DESC” and this will yield consistent results.
Therefore, make sure you are doing ordering on a column that makes the most sense in the current context. Make that obvious to the user, also. For perfomance reasons you will also want to add an index to that column.
This is the main paginating finder.
:page – REQUIRED, but defaults to 1 if false or nil
:per_page – defaults to CurrentModel.per_page
(which is 30 if not overridden)
:total_entries – use only if you manually count total
entries
:count – additional options that are passed on to
count
:finder – name of the finder method to use (default:
“find”)
All other options (conditions, order, …) are
forwarded to find and count calls.
# File lib/will_paginate/finders/base.rb, line 58 def paginate(*args, &block) options = args.pop page, per_page, total_entries = wp_parse_options(options) WillPaginate::Collection.create(page, per_page, total_entries) do |pager| query_options = options.except :page, :per_page, :total_entries wp_query(query_options, pager, args, &block) end end
Iterates through all records by loading one page at a time. This is useful for migrations or any other use case where you don’t want to load all the records in memory at once.
It uses paginate internally; therefore it accepts all of its
options. You can specify a starting page with :page (default
is 1). Default :order is "id", override
if necessary.
Jamis Buck describes this and also uses a more efficient way for MySQL.
# File lib/will_paginate/finders/base.rb, line 78 def paginated_each(options = {}, &block) options = { :order => 'id', :page => 1 }.merge options options[:page] = options[:page].to_i options[:total_entries] = 0 # skip the individual count queries total = 0 begin collection = paginate(options) total += collection.each(&block).size options[:page] += 1 end until collection.size < collection.per_page total end
# File lib/will_paginate/finders/base.rb, line 39 def per_page @per_page ||= 30 end
# File lib/will_paginate/finders/base.rb, line 43 def per_page=(limit) @per_page = limit.to_i end