DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world
ActiveRecord Each_by_page
Perform an operation on a set of models including ActiveRecord callbacks, without instantiating all models at once.
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.
module ActiveRecord
class Base
def each_by_page per_page, options = {}, &block
# By-id for model-modifying blocks
# Build SQL to get ids of all matching records using the options provided by the user
sql = construct_finder_sql(options.dup.merge({ :select => 'id' }))
# Get the results as an array of tiny hashes { "id" => "1" } and flatten them out to just the ids
all_ids = connection.select_all(sql).map { |h| h['id'] }
at_a_time = 0..(per_page-1)
# chop apart the all_ids array a segment at a time
begin
ids = all_ids.slice!(at_a_time)
ids_cases = []
ids.each_with_index { |id, i| ids_cases << "WHEN #{id} THEN #{i}" }
ids_cases = ids_cases.join(' ')
# Do the deed on this page of results
find(:all, options.merge(
:conditions => [ 'id IN (?)', ids ],
:order => "CASE id #{ids_cases} END"
)).each &block
end until all_ids.empty?
end
end
end
<a href="http://www.dweebd.com/ruby/activerecord-pagination-for-destructive-migrations/#comment-3">link to blog entry</a>






Comments
Snippets Manager replied on Sat, 2007/03/31 - 9:36am
module ActiveRecord class Base def self.each_by_page per_page, options = {}, &block sql = construct_finder_sql(options.dup.merge({ :select => "id" })) all_ids = connection.select_all(sql).map { |h| h["id"] } all_count = all_ids.length at_a_time = 0..(per_page-1) begin page_ids = all_ids.slice!(at_a_time) find(:all, :conditions => [ "id IN (?)", page_ids ] ).each &block end until all_ids.empty? return all_count end end end(I've also added some code to return the number of models in which the operation was performed)