ActiveRecord each_by_page
Step through and instantiate each member of the class and execute on it, but instantiate no more than per_page instances at any given time.
Safe for destructive actions or actions that modify the fields your :order or :conditions clauses operate on.
1 2 module ActiveRecord 3 class Base 4 def each_by_page per_page, options = {}, &block 5 # By-id for model-modifying blocks 6 # Build SQL to get ids of all matching records using the options provided by the user 7 sql = construct_finder_sql(options.dup.merge({ :select => 'id' })) 8 # Get the results as an array of tiny hashes { "id" => "1" } and flatten them out to just the ids 9 all_ids = connection.select_all(sql).map { |h| h['id'] } 10 at_a_time = 0..(per_page-1) 11 12 # chop apart the all_ids array a segment at a time 13 begin 14 ids = all_ids.slice!(at_a_time) 15 ids_cases = [] 16 ids.each_with_index { |id, i| ids_cases << "WHEN #{id} THEN #{i}" } 17 ids_cases = ids_cases.join(' ') 18 19 # Do the deed on this page of results 20 find(:all, options.merge( 21 :conditions => [ 'id IN (?)', ids ], 22 :order => "CASE id #{ids_cases} END" 23 )).each &block 24 25 end until all_ids.empty? 26 end 27 end 28 end
link to blog entry