Skip to content
This repository
Browse code

fix `total_pages`, `out_of_bounds?` for empty collections

Fixes #169
  • Loading branch information...
commit 26e87361bf8a4b86d9ea1cef2996edc58aca2187 1 parent d99caaa
Mislav Marohnić authored September 17, 2011
6  lib/will_paginate/active_record.rb
@@ -18,6 +18,8 @@ module WillPaginate
18 18
   module ActiveRecord
19 19
     # makes a Relation look like WillPaginate::Collection
20 20
     module RelationMethods
  21
+      include WillPaginate::CollectionMethods
  22
+
21 23
       attr_accessor :current_page
22 24
       attr_writer :total_entries, :wp_count_options
23 25
 
@@ -92,10 +94,6 @@ def empty?
92 94
         end
93 95
       end
94 96
 
95  
-      def total_pages
96  
-        (total_entries / limit_value.to_f).ceil
97  
-      end
98  
-
99 97
       def clone
100 98
         copy_will_paginate_data super
101 99
       end
57  lib/will_paginate/collection.rb
@@ -2,6 +2,38 @@
2 2
 require 'will_paginate/page_number'
3 3
 
4 4
 module WillPaginate
  5
+  # Any will_paginate-compatible collection should have these methods:
  6
+  #
  7
+  #   current_page, per_page, offset, total_entries, total_pages
  8
+  #
  9
+  # It can also define some of these optional methods:
  10
+  #
  11
+  #   out_of_bounds?, previous_page, next_page
  12
+  #
  13
+  # This module provides few of these methods.
  14
+  module CollectionMethods
  15
+    def total_pages
  16
+      total_entries.zero? ? 1 : (total_entries / per_page.to_f).ceil
  17
+    end
  18
+
  19
+    # current_page - 1 or nil if there is no previous page
  20
+    def previous_page
  21
+      current_page > 1 ? (current_page - 1) : nil
  22
+    end
  23
+
  24
+    # current_page + 1 or nil if there is no next page
  25
+    def next_page
  26
+      current_page < total_pages ? (current_page + 1) : nil
  27
+    end
  28
+
  29
+    # Helper method that is true when someone tries to fetch a page with a
  30
+    # larger number than the last page. Can be used in combination with flashes
  31
+    # and redirecting.
  32
+    def out_of_bounds?
  33
+      current_page > total_pages
  34
+    end
  35
+  end
  36
+
5 37
   # = The key to pagination
6 38
   # Arrays returned from paginating finds are, in fact, instances of this little
7 39
   # class. You may think of WillPaginate::Collection as an ordinary array with
@@ -18,7 +50,9 @@ module WillPaginate
18 50
   #   require 'will_paginate/collection'
19 51
   #   # WillPaginate::Collection is now available for use
20 52
   class Collection < Array
21  
-    attr_reader :current_page, :per_page, :total_entries, :total_pages
  53
+    include CollectionMethods
  54
+
  55
+    attr_reader :current_page, :per_page, :total_entries
22 56
 
23 57
     # Arguments to the constructor are the current page number, per-page limit
24 58
     # and the total number of entries. The last argument is optional because it
@@ -63,35 +97,16 @@ def self.create(page, per_page, total = nil)
63 97
       pager
64 98
     end
65 99
 
66  
-    # Helper method that is true when someone tries to fetch a page with a
67  
-    # larger number than the last page. Can be used in combination with flashes
68  
-    # and redirecting.
69  
-    def out_of_bounds?
70  
-      current_page > total_pages
71  
-    end
72  
-
73 100
     # Current offset of the paginated collection. If we're on the first page,
74 101
     # it is always 0. If we're on the 2nd page and there are 30 entries per page,
75 102
     # the offset is 30. This property is useful if you want to render ordinals
76 103
     # side by side with records in the view: simply start with offset + 1.
77 104
     def offset
78  
-      @current_page.to_offset(per_page).to_i
79  
-    end
80  
-
81  
-    # current_page - 1 or nil if there is no previous page
82  
-    def previous_page
83  
-      current_page > 1 ? (current_page - 1) : nil
  105
+      current_page.to_offset(per_page).to_i
84 106
     end
85 107
 
86  
-    # current_page + 1 or nil if there is no next page
87  
-    def next_page
88  
-      current_page < total_pages ? (current_page + 1) : nil
89  
-    end
90  
-    
91  
-    # sets the <tt>total_entries</tt> property and calculates <tt>total_pages</tt>
92 108
     def total_entries=(number)
93 109
       @total_entries = number.to_i
94  
-      @total_pages   = (@total_entries / per_page.to_f).ceil
95 110
     end
96 111
 
97 112
     # This is a magic wrapper for the original Array#replace method. It serves
6  lib/will_paginate/data_mapper.rb
@@ -30,6 +30,8 @@ def paginate(options)
30 30
     end
31 31
 
32 32
     module CollectionMethods
  33
+      include WillPaginate::CollectionMethods
  34
+
33 35
       attr_accessor :current_page
34 36
 
35 37
       def paginated?
@@ -58,10 +60,6 @@ def total_entries
58 60
         end
59 61
       end
60 62
 
61  
-      def total_pages
62  
-        (total_entries / per_page.to_f).ceil
63  
-      end
64  
-
65 63
       def to_a
66 64
         ::WillPaginate::Collection.create(current_page, per_page) do |col|
67 65
           col.replace super
3  lib/will_paginate/sequel.rb
... ...
@@ -1,10 +1,13 @@
1 1
 require 'sequel'
2 2
 require 'sequel/extensions/pagination'
  3
+require 'will_paginate/collection'
3 4
 
4 5
 module WillPaginate
5 6
   # Sequel already supports pagination; we only need to make the
6 7
   # resulting dataset look a bit more like WillPaginate::Collection
7 8
   module SequelMethods
  9
+    include WillPaginate::CollectionMethods
  10
+
8 11
     def total_pages
9 12
       page_count
10 13
     end
20  spec/collection_spec.rb
@@ -71,12 +71,20 @@
71 71
     end
72 72
   end
73 73
 
74  
-  it "should show out of bounds when page number is too high" do
75  
-    create(2, 3, 2).should be_out_of_bounds
76  
-  end
77  
-    
78  
-  it "should not show out of bounds when inside collection" do
79  
-    create(1, 3, 2).should_not be_out_of_bounds
  74
+  describe "out of bounds" do
  75
+    it "is out of bounds when page number is too high" do
  76
+      create(2, 3, 2).should be_out_of_bounds
  77
+    end
  78
+
  79
+    it "isn't out of bounds when inside collection" do
  80
+      create(1, 3, 2).should_not be_out_of_bounds
  81
+    end
  82
+
  83
+    it "isn't out of bounds when the collection is empty" do
  84
+      collection = create(1, 3, 0)
  85
+      collection.should_not be_out_of_bounds
  86
+      collection.total_pages.should == 1
  87
+    end
80 88
   end
81 89
 
82 90
   describe "guessing total count" do
4  spec/finders/active_record_spec.rb
@@ -179,6 +179,10 @@
179 179
     it "should count with group" do
180 180
       Developer.group(:salary).page(1).total_entries.should == 4
181 181
     end
  182
+
  183
+    it "should not have zero total_pages when the result set is empty" do
  184
+      Developer.where("1 = 2").page(1).total_pages.should == 1
  185
+    end
182 186
   end
183 187
   
184 188
   it "should not ignore :select parameter when it says DISTINCT" do
4  spec/finders/data_mapper_spec.rb
@@ -76,4 +76,8 @@
76 76
     Animal.all(:limit => 2).page(2).per_page.should == 2
77 77
   end
78 78
 
  79
+  it "has total_pages at 1 for empty collections" do
  80
+    Animal.all(:conditions => ['1=2']).page(1).total_pages.should == 1
  81
+  end
  82
+
79 83
 end if datamapper_loaded

0 notes on commit 26e8736

Please sign in to comment.
Something went wrong with that request. Please try again.