Skip to content

Instantly share code, notes, and snippets.

@harvesthq
Created June 29, 2009 13:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save harvesthq/137616 to your computer and use it in GitHub Desktop.
Save harvesthq/137616 to your computer and use it in GitHub Desktop.
# This is a mechanism we use often in our migrations. When we have a migration
# that hits every record of a large table, this looping mechanism takes the
# bite away from the migration. This allows us to be transactional in our
# migration while avoiding aggressive locking of the table. Ultimately
# allowing us to do migratory deployments even more frequently during high
# usage areas of the day.
#
# Further, some long migrations that we'd run over a weekend may exceed the
# max transaction time set on our MySQL server. Running smaller transactions
# avoids this sensible restriction.
#
# We place this bit of code in config/initializers. Transactional loop requires
# will_paginate to execute.
class ActiveRecord::Migration
def self.transactional_loop(active_record_class, paginate_options={}, &block)
page = 1
loop do
no_more_records = true
active_record_class.transaction do
active_record_class.paginate({:page => page, :per_page => 100}.merge(paginate_options)).each do |active_record_instance|
no_more_records = false
block.call(active_record_instance)
end
page += page + 1
end
break if no_more_records
end
end
end
class SomeMigration < ActiveRecord::Migration
def self.up
transactional_loop(Company, :include => :invoicing_profile) do |company|
# do something to or with company
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment