lib/will_paginate/finder.rb in will_paginate-2.1.0 vs lib/will_paginate/finder.rb in will_paginate-2.2.0
- old
+ new
@@ -1,10 +1,10 @@
require 'will_paginate/core_ext'
module WillPaginate
# A mixin for ActiveRecord::Base. Provides +per_page+ class method
- # and makes +paginate+ finders possible with some method_missing magic.
+ # and hooks things up to provide paginating finders.
#
# Find out more in WillPaginate::Finder::ClassMethods
#
module Finder
def self.included(base)
@@ -16,13 +16,13 @@
end
end
# = Paginating finders for ActiveRecord models
#
- # WillPaginate adds +paginate+ and +per_page+ methods to ActiveRecord::Base
- # class methods and associations. It also hooks into +method_missing+ to
- # intercept pagination calls to dynamic finders such as
+ # WillPaginate adds +paginate+, +per_page+ and other methods to
+ # ActiveRecord::Base class methods and associations. It also hooks into
+ # +method_missing+ to intercept pagination calls to dynamic finders such as
# +paginate_by_user_id+ and translate them to ordinary finders
# (+find_all_by_user_id+ in this case).
#
# In short, paginating finders are equivalent to ActiveRecord finders; the
# only difference is that we start with "paginate" instead of "find" and
@@ -82,9 +82,34 @@
pager.replace send(finder, *args, &block)
# magic counting for user convenience:
pager.total_entries = wp_count(count_options, args, finder) unless pager.total_entries
end
+ end
+
+ # Iterates through all records by loading one page at a time. This is useful
+ # for migrations or any other use case where you don't want to load all the
+ # records in memory at once.
+ #
+ # It uses +paginate+ internally; therefore it accepts all of its options.
+ # You can specify a starting page with <tt>:page</tt> (default is 1). Default
+ # <tt>:order</tt> is <tt>"id"</tt>, override if necessary.
+ #
+ # See http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord where
+ # Jamis Buck describes this and also uses a more efficient way for MySQL.
+ def paginated_each(options = {}, &block)
+ options = { :order => 'id', :page => 1 }.merge options
+ options[:page] = options[:page].to_i
+ options[:total_entries] = 0 # skip the individual count queries
+ total = 0
+
+ begin
+ collection = paginate(options)
+ total += collection.each(&block).size
+ options[:page] += 1
+ end until collection.size < collection.per_page
+
+ total
end
# Wraps +find_by_sql+ by simply adding LIMIT and OFFSET to your SQL string
# based on the params otherwise used by paginating finds: +page+ and
# +per_page+.