Using will_paginate with ActiveRecord
The primary integration for will_paginate
is with ActiveRecord, the default ORM for Ruby on Rails. It extends ActiveRecord::Base
and ActiveRecord::Relation
to provide simple and chainable pagination methods.
The .paginate()
Method
The main method is .paginate()
. It's a paginating finder that works similarly to ActiveRecord's own finders. It returns a relation that is aware of its pagination state.
Parameters
:page
(required): The current page number to retrieve. Usuallyparams[:page]
.:per_page
: The number of records to retrieve per page. This overrides any model-level or global settings.:total_entries
: Manually sets the total number of records. This is useful for performance, as it skips theCOUNT
query thatwill_paginate
would otherwise perform.
Example
# Get the first page with 20 posts per page
@posts = Post.paginate(page: params[:page], per_page: 20)
# Get page 3, letting the model/global setting define per_page
@users = User.paginate(page: 3)
The .page()
Shorthand
For a more modern, chainable syntax that integrates cleanly with other ActiveRecord scopes, use the .page()
method.
# Chainable and clean
@posts = Post.where(published: true).page(params[:page]).order(id: :desc)
You can set the number of items per page by chaining .per_page()
or .limit()
:
@posts = Post.page(params[:page]).per_page(5)
@posts = Post.page(params[:page]).limit(5) # `limit` is an alias for per_page
Returned Collection
Both .paginate()
and .page()
return an ActiveRecord::Relation
instance that has been extended with WillPaginate::Collection
methods. This means you can iterate over it just like a regular collection of records, but you also have access to helpful pagination attributes:
collection.current_page
collection.per_page
collection.total_entries
collection.total_pages
collection.offset
collection.previous_page
collection.next_page
Advanced Querying
will_paginate
works seamlessly with most advanced ActiveRecord queries.
Scopes and Associations
# Paginate results from a scope
@poor_developers = Developer.poor.paginate(page: 1)
# Paginate an association
@project = Project.find(1)
@developers = @project.developers.paginate(page: 1)
Joins
You can paginate queries that include joins.
@developers = Developer.joins(:projects)
.where('projects.id = ?', 1)
.paginate(page: 1)
Grouping
Pagination with grouped queries is also supported. will_paginate
is smart enough to correctly calculate the total number of entries.
@salaries = Developer.select('salary').group('salary').page(1)
# This will correctly count the number of groups, not the total number of developers.
@salaries.total_entries # => 4 (for example)
Custom SQL with paginate_by_sql
For complex queries where ActiveRecord's query interface isn't sufficient, you can use paginate_by_sql
. This method takes a raw SQL string and paginates the results by adding the appropriate LIMIT
and OFFSET
clauses.
sql = "SELECT * FROM topics WHERE content LIKE '%ruby%'"
@topics = Topic.paginate_by_sql(sql, page: params[:page], per_page: 10)
will_paginate
will attempt to generate a COUNT
query automatically. If this fails or you want to optimize it, you can provide a :total_entries
option.