Paginating Plain Arrays and Enumerable Collections

Besides its deep integration with ORMs, will_paginate provides a powerful utility for paginating any in-memory Array or Enumerable collection. This is especially useful when dealing with data from external APIs, cached results, or any static list of items.

Array#paginate

The will_paginate/array module extends Ruby's core Array class with a paginate method. The result is a WillPaginate::Collection instance, which is an array-like object with additional pagination properties.

Usage

To use this feature, you may need to explicitly require it if you are not in a Rails environment where it's automatically loaded:

require 'will_paginate/array'

Now you can call paginate on any array:

arr = ('a'..'z').to_a # An array of 26 letters

# Get the first page, with 5 items per page
paged_collection = arr.paginate(page: 1, per_page: 5)

paged_collection.length         #=> 5
paged_collection                #=> ['a', 'b', 'c', 'd', 'e']

# Get the second page
arr.paginate(page: 2, per_page: 5)  #=> ['f', 'g', 'h', 'i', 'j']

# The collection knows its pagination state
paged_collection.total_entries  #=> 26
paged_collection.total_pages    #=> 6

Parameters

  • :page: The current page number (defaults to 1).
  • :per_page: The number of items per page (defaults to WillPaginate.per_page, which is 30).
  • :total_entries: The total number of items in the original array. By default, this is simply self.length, so you rarely need to specify it.

Manual Creation with WillPaginate::Collection

For more advanced use cases, you can manually construct a WillPaginate::Collection. This gives you full control over creating a paginated collection from any data source, not just an existing array.

The WillPaginate::Collection.create method is perfect for this. It takes the page, per_page, and total entries, and yields a new, empty collection object for you to populate.

Example

Imagine you are fetching data from a remote API that already provides pagination information.

require 'will_paginate/collection'

# Fictional API client
api_response = ApiClient.get_users(page: 2, per_page: 10)
# api_response.users => array of user data
# api_response.total_count => total number of users available

@users = WillPaginate::Collection.create(2, 10, api_response.total_count) do |pager|
  # Populate the pager with the results for the current page
  pager.replace(api_response.users)
end

# Now @users can be passed directly to the `will_paginate` view helper
# <%= will_paginate @users %>

This approach is powerful because it lets you adapt any data source to the API that the will_paginate view helpers expect.