Skip to content

Instantly share code, notes, and snippets.

@marshall-lee
Last active November 15, 2018 11:15
Show Gist options
  • Save marshall-lee/c6ec5a855376cdf35c2f to your computer and use it in GitHub Desktop.
Save marshall-lee/c6ec5a855376cdf35c2f to your computer and use it in GitHub Desktop.
Online (non-blocking) ActiveRecord migrations using pt-online-schema-change utility from Percona Toolkit
# Online (non-blocking) ActiveRecord migrations using pt-online-schema-change utility from Percona Toolkit.
#
# In your Rails app put it as lib/online_change_table.rb
# Now you can use it in your migration file:
#
# require 'online_change_table'
#
# class AddSomethingToSomethings < ActiveRecord::Migration
# def up
# online_change_table :somethings do |t|
# t.column :a, :string
# t.column :b, :integer, default: 0
# t.change :c, :text, default: '...'
# end
# end
# end
#
# Tested only on ActiveRecord 4.1
# Maybe some time i will release it as a gem :D
class ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter
def online_change_table(table_name)
recorder = ActiveRecord::Migration::CommandRecorder.new(self)
yield update_table_definition(table_name, recorder)
operations = recorder.commands
sqls = operations.map do |command, args|
table, arguments = args.shift, args
method = :"#{command}_sql"
if respond_to?(method, true)
send(method, table, *arguments)
else
raise "Unknown method called : #{method}(#{arguments.inspect})"
end
end.flatten.join(", ")
config = ActiveRecord::Base.configurations[Rails.env]
dsn = "D=#{config['database']},t=#{table_name}"
dsn << ",h=#{config['host']}" if config['host']
dsn << ",u=#{config['username']}" if config['username']
dsn << ",p=#{config['password']}" if config['password']
dsn << ",P=#{config['port']}" if config['port']
dsn << ",A=#{config['encoding']}" if config['encoding']
ok = system 'pt-online-schema-change', '--alter', sqls, dsn, '--execute'
fail unless ok
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment