Create a gist now

Instantly share code, notes, and snippets.

# 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
page += page + 1
break if no_more_records
class SomeMigration < ActiveRecord::Migration
def self.up
transactional_loop(Company, :include => :invoicing_profile) do |company|
# do something to or with company
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment