It is a frequent requirement that your Rails views not display all of the records in an array on one page. In those cases, you need to implement pagination. That functionality is made simple with the use of the WillPaginate gem.
NOTE: WillPaginate requires that your Ruby gems be at least v.1.2.
(Most of this information comes from the WillPaginate documentation.)
The WillPaginate gem is built by GitHub. Add GitHub to your gem sources (once per machine):
$ gem sources -a http://gems.github.com
You don't need to do this with updated rubygems (1.6 or greater) as both will_paginate and rubygems have moved to gemcutter hosting.
Install the library:
$ gem install mislav-will_paginate
To enable the library simply load it in “config/environment.rb”
Rails::Initializer.run do |config| ... end require "will_paginate"
Don't put it before or inside the Rails::Initializer block because the Rails framework is not yet loaded at that point of execution.
You will want to use use Gem dependencies to load the will_paginate gem. Simply add the following code to config/environment.rb:
Rails::Initializer.run do |config| ... config.gem 'mislav-will_paginate', :lib => 'will_paginate', :source => 'http://gems.github.com' ... end
Use a paginate finder in the controller:
page = params[:page] || 1 @posts = Post.paginate_by_board_id @board.id, :page => page, :order => 'updated_at DESC'
Paginate works just like find — it just doesn't fetch all the records. Don't forget to tell it which page you want, or it will complain! Read more on WillPaginate::Finder::ClassMethods.
Render the posts in your view like you would normally do. When you need to render pagination, just stick this in:
<%= will_paginate @posts %>
Will_paginate determines how many records to display per page by calling the per_page class method for the model being returned by the query. You can define the per_page method like this:
class Post < ActiveRecord::Base cattr_reader :per_page @@per_page = 50 end
… or like this:
class Post < ActiveRecord::Base def self.per_page 50 end end
If your class doesn't specify, the default :per_page value is 30. You can also always specify this value explicitly in your controller:
@posts = Post.paginate :page => params[:page] || 1, :per_page => 50
The paginate finder wraps the original finder and returns a collection that has some extra properties. You can use the returned collection as you would with any ActiveRecord result set. WillPaginate view helpers also need that object to be able to render pagination:
<ol> <% @posts.each do |post| -%> <li><%= link_to post.title, post %></li> <% end -%> </ol>
Discussion