Module: WillPaginate::Finders::Base
- Included in:
- ActiveRecord, ActiveResource, DataMapper
- Defined in:
- lib/will_paginate/finders/base.rb
Overview
Database-agnostic finder module
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:
-
ActiveRecord
-
DataMapper
-
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.
The importance of SQL’s ORDER BY
In 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.
Instance Method Summary collapse
-
#paginate(*args, &block) ⇒ Object
This is the main paginating finder.
-
#paginated_each(options = {}, &block) ⇒ Object
Iterates through all records by loading one page at a time.
- #per_page ⇒ Object
- #per_page=(limit) ⇒ Object
Instance Method Details
#paginate(*args, &block) ⇒ Object
This is the main paginating finder.
Special parameters for paginating finders
-
:page
– REQUIRED, but defaults to 1 if false or nil -
:per_page
– defaults toCurrentModel.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 tocount
-
:finder
– name of the finder method to use (default: “find”)
All other options (conditions
, order
, …) are forwarded to find
and count
calls.
58 59 60 61 62 63 64 65 66 |
# File 'lib/will_paginate/finders/base.rb', line 58 def paginate(*args, &block) = args.pop page, per_page, total_entries = () WillPaginate::Collection.create(page, per_page, total_entries) do |pager| = .except :page, :per_page, :total_entries wp_query(, pager, args, &block) end end |
#paginated_each(options = {}, &block) ⇒ Object
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.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/will_paginate/finders/base.rb', line 78 def paginated_each( = {}, &block) = { :order => 'id', :page => 1 }.merge [:page] = [:page].to_i [:total_entries] = 0 # skip the individual count queries total = 0 begin collection = paginate() total += collection.each(&block).size [:page] += 1 end until collection.size < collection.per_page total end |
#per_page ⇒ Object
39 40 41 |
# File 'lib/will_paginate/finders/base.rb', line 39 def per_page @per_page ||= 30 end |
#per_page=(limit) ⇒ Object
43 44 45 |
# File 'lib/will_paginate/finders/base.rb', line 43 def per_page=(limit) @per_page = limit.to_i end |