Class | Cms::Behaviors::Pagination::Collection |
In: |
lib/cms/behaviors/pagination.rb
|
Parent: | Array |
current_page | [R] | |
per_page | [R] | |
total_entries | [R] | |
total_pages | [R] |
Just like new, but yields the object after instantiation and returns it afterwards. This is very useful for manual pagination:
@entries = WillPaginate::Collection.create(1, 10) do |pager| result = Post.find(:all, :limit => pager.per_page, :offset => pager.offset) # inject the result array into the paginated collection: pager.replace(result) unless pager.total_entries # the pager didn't manage to guess the total count, do it manually pager.total_entries = Post.count end end
The possibilities with this are endless. For another example, here is how WillPaginate used to define pagination for Array instances:
Array.class_eval do def paginate(page = 1, per_page = 15) WillPaginate::Collection.create(page, per_page, size) do |pager| pager.replace self[pager.offset, pager.per_page].to_a end end end
The Array#paginate API has since then changed, but this still serves as a fine example of WillPaginate::Collection usage.
# File lib/cms/behaviors/pagination.rb, line 59 59: def self.create(page, per_page, total = nil, &block) 60: pager = new(page, per_page, total) 61: yield pager 62: pager 63: end
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 is best to do lazy counting; in other words, count conditionally after populating the collection using the replace method.
# File lib/cms/behaviors/pagination.rb, line 23 23: def initialize(page, per_page, total = nil) 24: @current_page = page.to_i 25: raise InvalidPage.new(page, @current_page) if @current_page < 1 26: @per_page = per_page.to_i 27: raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1 28: 29: self.total_entries = total if total 30: end
current_page + 1 or nil if there is no next page
# File lib/cms/behaviors/pagination.rb, line 86 86: def next_page 87: current_page < total_pages ? (current_page + 1) : nil 88: 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 besides your records: simply start with offset + 1.
# File lib/cms/behaviors/pagination.rb, line 76 76: def offset 77: (current_page - 1) * per_page 78: 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.
# File lib/cms/behaviors/pagination.rb, line 68 68: def out_of_bounds? 69: current_page > total_pages 70: end
current_page - 1 or nil if there is no previous page
# File lib/cms/behaviors/pagination.rb, line 81 81: def previous_page 82: current_page > 1 ? (current_page - 1) : nil 83: end
This is a magic wrapper for the original Array#replace method. It serves for populating the paginated collection after initialization.
Why magic? Because it tries to guess the total number of entries judging by the size of given array. If it is shorter than per_page limit, then we know we‘re on the last page. This trick is very useful for avoiding unnecessary hits to the database to do the counting after we fetched the data for the current page.
However, after using replace you should always test the value of total_entries and set it to a proper value if it‘s nil. See the example in create.
# File lib/cms/behaviors/pagination.rb, line 107 107: def replace(array) 108: result = super 109: 110: # The collection is shorter then page limit? Rejoice, because 111: # then we know that we are on the last page! 112: if total_entries.nil? and length < per_page and (current_page == 1 or length > 0) 113: self.total_entries = offset + length 114: end 115: 116: result 117: end