Skip to content

Commit

Permalink
fix total_pages, out_of_bounds? for empty collections
Browse files Browse the repository at this point in the history
  • Loading branch information
mislav committed Sep 17, 2011
1 parent d99caaa commit 26e8736
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 35 deletions.
6 changes: 2 additions & 4 deletions lib/will_paginate/active_record.rb
Expand Up @@ -18,6 +18,8 @@ module WillPaginate
module ActiveRecord
# makes a Relation look like WillPaginate::Collection
module RelationMethods
include WillPaginate::CollectionMethods

attr_accessor :current_page
attr_writer :total_entries, :wp_count_options

Expand Down Expand Up @@ -92,10 +94,6 @@ def empty?
end
end

def total_pages
(total_entries / limit_value.to_f).ceil
end

def clone
copy_will_paginate_data super
end
Expand Down
57 changes: 36 additions & 21 deletions lib/will_paginate/collection.rb
Expand Up @@ -2,6 +2,38 @@
require 'will_paginate/page_number'

module WillPaginate
# Any will_paginate-compatible collection should have these methods:
#
# current_page, per_page, offset, total_entries, total_pages
#
# It can also define some of these optional methods:
#
# out_of_bounds?, previous_page, next_page
#
# This module provides few of these methods.
module CollectionMethods
def total_pages
total_entries.zero? ? 1 : (total_entries / per_page.to_f).ceil
end

# current_page - 1 or nil if there is no previous page
def previous_page
current_page > 1 ? (current_page - 1) : nil
end

# current_page + 1 or nil if there is no next page
def next_page
current_page < total_pages ? (current_page + 1) : nil
end

# Helper method that is true when someone tries to fetch a page with a
# larger number than the last page. Can be used in combination with flashes
# and redirecting.
def out_of_bounds?
current_page > total_pages
end
end

# = The key to pagination
# Arrays returned from paginating finds are, in fact, instances of this little
# class. You may think of WillPaginate::Collection as an ordinary array with
Expand All @@ -18,7 +50,9 @@ module WillPaginate
# require 'will_paginate/collection'
# # WillPaginate::Collection is now available for use
class Collection < Array
attr_reader :current_page, :per_page, :total_entries, :total_pages
include CollectionMethods

attr_reader :current_page, :per_page, :total_entries

# Arguments to the constructor are the current page number, per-page limit
# and the total number of entries. The last argument is optional because it
Expand Down Expand Up @@ -63,35 +97,16 @@ def self.create(page, per_page, total = nil)
pager
end

# Helper method that is true when someone tries to fetch a page with a
# larger number than the last page. Can be used in combination with flashes
# and redirecting.
def out_of_bounds?
current_page > total_pages
end

# Current offset of the paginated collection. If we're on the first page,
# it is always 0. If we're on the 2nd page and there are 30 entries per page,
# the offset is 30. This property is useful if you want to render ordinals
# side by side with records in the view: simply start with offset + 1.
def offset
@current_page.to_offset(per_page).to_i
end

# current_page - 1 or nil if there is no previous page
def previous_page
current_page > 1 ? (current_page - 1) : nil
current_page.to_offset(per_page).to_i
end

# current_page + 1 or nil if there is no next page
def next_page
current_page < total_pages ? (current_page + 1) : nil
end

# sets the <tt>total_entries</tt> property and calculates <tt>total_pages</tt>
def total_entries=(number)
@total_entries = number.to_i
@total_pages = (@total_entries / per_page.to_f).ceil
end

# This is a magic wrapper for the original Array#replace method. It serves
Expand Down
6 changes: 2 additions & 4 deletions lib/will_paginate/data_mapper.rb
Expand Up @@ -30,6 +30,8 @@ def paginate(options)
end

module CollectionMethods
include WillPaginate::CollectionMethods

attr_accessor :current_page

def paginated?
Expand Down Expand Up @@ -58,10 +60,6 @@ def total_entries
end
end

def total_pages
(total_entries / per_page.to_f).ceil
end

def to_a
::WillPaginate::Collection.create(current_page, per_page) do |col|
col.replace super
Expand Down
3 changes: 3 additions & 0 deletions lib/will_paginate/sequel.rb
@@ -1,10 +1,13 @@
require 'sequel'
require 'sequel/extensions/pagination'
require 'will_paginate/collection'

module WillPaginate
# Sequel already supports pagination; we only need to make the
# resulting dataset look a bit more like WillPaginate::Collection
module SequelMethods
include WillPaginate::CollectionMethods

def total_pages
page_count
end
Expand Down
20 changes: 14 additions & 6 deletions spec/collection_spec.rb
Expand Up @@ -71,12 +71,20 @@
end
end

it "should show out of bounds when page number is too high" do
create(2, 3, 2).should be_out_of_bounds
end

it "should not show out of bounds when inside collection" do
create(1, 3, 2).should_not be_out_of_bounds
describe "out of bounds" do
it "is out of bounds when page number is too high" do
create(2, 3, 2).should be_out_of_bounds
end

it "isn't out of bounds when inside collection" do
create(1, 3, 2).should_not be_out_of_bounds
end

it "isn't out of bounds when the collection is empty" do
collection = create(1, 3, 0)
collection.should_not be_out_of_bounds
collection.total_pages.should == 1
end
end

describe "guessing total count" do
Expand Down
4 changes: 4 additions & 0 deletions spec/finders/active_record_spec.rb
Expand Up @@ -179,6 +179,10 @@
it "should count with group" do
Developer.group(:salary).page(1).total_entries.should == 4
end

it "should not have zero total_pages when the result set is empty" do
Developer.where("1 = 2").page(1).total_pages.should == 1
end
end

it "should not ignore :select parameter when it says DISTINCT" do
Expand Down
4 changes: 4 additions & 0 deletions spec/finders/data_mapper_spec.rb
Expand Up @@ -76,4 +76,8 @@
Animal.all(:limit => 2).page(2).per_page.should == 2
end

it "has total_pages at 1 for empty collections" do
Animal.all(:conditions => ['1=2']).page(1).total_pages.should == 1
end

end if datamapper_loaded

0 comments on commit 26e8736

Please sign in to comment.