2011-07-19 08:47:13 -04:00
require " active_support/core_ext/class/attribute_accessors "
2012-01-13 16:34:54 -05:00
require 'set'
2010-12-09 20:14:58 -05:00
2005-03-01 09:27:32 -05:00
module ActiveRecord
2010-01-16 16:56:20 -05:00
# Exception that can be raised to stop migrations from going backwards.
class IrreversibleMigration < ActiveRecordError
2005-03-01 09:27:32 -05:00
end
2007-05-25 22:36:55 -04:00
2005-10-31 10:43:02 -05:00
class DuplicateMigrationVersionError < ActiveRecordError #:nodoc:
def initialize ( version )
super ( " Multiple migrations have the version number #{ version } " )
end
end
2007-05-25 22:36:55 -04:00
2008-05-07 01:59:34 -04:00
class DuplicateMigrationNameError < ActiveRecordError #:nodoc:
def initialize ( name )
super ( " Multiple migrations have the name #{ name } " )
end
end
2008-03-28 17:21:01 -04:00
class UnknownMigrationVersionError < ActiveRecordError #:nodoc:
def initialize ( version )
super ( " No migration with version number #{ version } " )
end
end
2007-10-17 17:35:19 -04:00
class IllegalMigrationNameError < ActiveRecordError #:nodoc:
def initialize ( name )
super ( " Illegal name for migration file: #{ name } \n \t (only lower case letters, numbers, and '_' allowed) " )
end
end
2012-06-05 20:15:16 -04:00
class PendingMigrationError < ActiveRecordError #:nodoc:
def initialize
2013-07-28 14:41:36 -04:00
super ( " Migrations are pending; run 'bin/rake db:migrate RAILS_ENV= #{ :: Rails . env } ' to resolve this issue. " )
2012-06-05 20:15:16 -04:00
end
end
2010-06-16 13:38:14 -04:00
# = Active Record Migrations
2010-08-14 01:13:00 -04:00
#
# Migrations can manage the evolution of a schema used by several physical
2010-06-15 14:41:30 -04:00
# databases. It's a solution to the common problem of adding a field to make
# a new feature work in your local database, but being unsure of how to
2010-08-14 01:13:00 -04:00
# push that change to other developers and to the production server. With
2010-06-15 14:41:30 -04:00
# migrations, you can describe the transformations in self-contained classes
2010-08-14 01:13:00 -04:00
# that can be checked into version control systems and executed against
2010-06-15 14:41:30 -04:00
# another database that might be one, two, or five versions behind.
2005-07-04 14:51:02 -04:00
#
# Example of a simple migration:
#
# class AddSsl < ActiveRecord::Migration
2010-11-17 17:52:52 -05:00
# def up
2012-09-30 19:48:22 -04:00
# add_column :accounts, :ssl_enabled, :boolean, default: true
2005-07-04 14:51:02 -04:00
# end
2005-11-13 22:51:39 -05:00
#
2010-11-17 17:52:52 -05:00
# def down
2005-07-04 14:51:02 -04:00
# remove_column :accounts, :ssl_enabled
# end
# end
#
2010-08-14 01:13:00 -04:00
# This migration will add a boolean flag to the accounts table and remove it
# if you're backing out of the migration. It shows how all migrations have
2011-06-06 15:53:08 -04:00
# two methods +up+ and +down+ that describes the transformations
2010-06-15 14:41:30 -04:00
# required to implement or remove the migration. These methods can consist
2012-09-30 19:48:22 -04:00
# of both the migration specific methods like +add_column+ and +remove_column+,
2010-08-14 01:13:00 -04:00
# but may also contain regular Ruby code for generating data needed for the
2010-06-15 14:41:30 -04:00
# transformations.
2005-07-04 14:51:02 -04:00
#
# Example of a more complex migration that also needs to initialize data:
#
# class AddSystemSettings < ActiveRecord::Migration
2010-11-17 17:52:52 -05:00
# def up
2012-09-30 22:01:43 -04:00
# create_table :system_settings do |t|
2007-10-07 23:18:18 -04:00
# t.string :name
# t.string :label
2011-06-26 14:42:39 -04:00
# t.text :value
2007-10-07 23:18:18 -04:00
# t.string :type
2011-06-26 14:42:39 -04:00
# t.integer :position
2005-07-04 14:51:02 -04:00
# end
2005-11-13 22:51:39 -05:00
#
2012-09-30 19:48:22 -04:00
# SystemSetting.create name: 'notice',
# label: 'Use notice?',
# value: 1
2005-07-04 14:51:02 -04:00
# end
2005-11-13 22:51:39 -05:00
#
2010-11-17 17:52:52 -05:00
# def down
2005-07-04 14:51:02 -04:00
# drop_table :system_settings
# end
# end
#
2012-09-30 19:48:22 -04:00
# This migration first adds the +system_settings+ table, then creates the very
2010-06-15 14:41:30 -04:00
# first row in it using the Active Record model that relies on the table. It
2012-09-30 19:48:22 -04:00
# also uses the more advanced +create_table+ syntax where you can specify a
2010-06-15 14:41:30 -04:00
# complete table schema in one block call.
2005-07-04 14:51:02 -04:00
#
# == Available transformations
#
2012-09-30 19:48:22 -04:00
# * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
2010-06-15 14:41:30 -04:00
# makes the table object available to a block that can then add columns to it,
2012-09-30 19:48:22 -04:00
# following the same format as +add_column+. See example above. The options hash
2010-08-14 01:13:00 -04:00
# is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
2010-06-15 14:41:30 -04:00
# table definition.
2005-07-04 14:51:02 -04:00
# * <tt>drop_table(name)</tt>: Drops the table called +name+.
2012-09-30 19:48:22 -04:00
# * <tt>change_table(name, options)</tt>: Allows to make column alterations to
2013-03-27 11:44:58 -04:00
# the table called +name+. It makes the table object available to a block that
2012-09-30 19:48:22 -04:00
# can then add/remove columns, indexes or foreign keys to it.
2010-08-14 01:13:00 -04:00
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
2010-06-15 14:41:30 -04:00
# to +new_name+.
2010-08-14 01:13:00 -04:00
# * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
2010-06-15 14:41:30 -04:00
# to the table called +table_name+
2005-07-04 14:51:02 -04:00
# named +column_name+ specified to be one of the following types:
2010-08-14 01:13:00 -04:00
# <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>,
2010-06-15 14:41:30 -04:00
# <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
2010-06-24 00:25:49 -04:00
# <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be
2012-09-30 19:48:22 -04:00
# specified by passing an +options+ hash like <tt>{ default: 11 }</tt>.
2010-08-14 01:13:00 -04:00
# Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
2012-09-30 19:48:22 -04:00
# <tt>{ limit: 50, null: false }</tt>) -- see
2010-06-15 14:41:30 -04:00
# ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
# a column but keeps the type and content.
2010-08-14 01:13:00 -04:00
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
2010-06-15 14:41:30 -04:00
# the column to a different type using the same parameters as add_column.
2011-11-07 00:03:33 -05:00
# * <tt>remove_column(table_name, column_names)</tt>: Removes the column listed in
# +column_names+ from the table called +table_name+.
2010-08-14 01:13:00 -04:00
# * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
2010-06-15 14:41:30 -04:00
# with the name of the column. Other options include
2011-11-04 16:45:24 -04:00
# <tt>:name</tt>, <tt>:unique</tt> (e.g.
2012-09-30 19:48:22 -04:00
# <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
2012-10-08 04:50:56 -04:00
# (e.g. <tt>{ order: { name: :desc } }</tt>).
2012-09-30 19:48:22 -04:00
# * <tt>remove_index(table_name, column: column_name)</tt>: Removes the index
2011-06-17 14:55:07 -04:00
# specified by +column_name+.
2012-09-30 19:48:22 -04:00
# * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
2011-06-17 14:55:07 -04:00
# specified by +index_name+.
2005-07-04 14:51:02 -04:00
#
# == Irreversible transformations
#
2010-08-14 01:13:00 -04:00
# Some transformations are destructive in a manner that cannot be reversed.
# Migrations of that kind should raise an <tt>ActiveRecord::IrreversibleMigration</tt>
2010-06-15 14:41:30 -04:00
# exception in their +down+ method.
2005-07-04 14:51:02 -04:00
#
2005-07-05 03:19:20 -04:00
# == Running migrations from within Rails
#
2005-11-13 22:51:39 -05:00
# The Rails package has several tools to help create and apply migrations.
#
2009-04-23 12:55:42 -04:00
# To generate a new migration, you can use
2010-02-06 11:18:10 -05:00
# rails generate migration MyNewMigration
2008-03-26 08:27:52 -04:00
#
2005-11-13 22:51:39 -05:00
# where MyNewMigration is the name of your migration. The generator will
2010-08-14 01:13:00 -04:00
# create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
# in the <tt>db/migrate/</tt> directory where <tt>timestamp</tt> is the
2010-06-15 14:41:30 -04:00
# UTC formatted date and time that the migration was generated.
2008-03-26 08:27:52 -04:00
#
2010-11-17 17:54:08 -05:00
# You may then edit the <tt>up</tt> and <tt>down</tt> methods of
2007-11-07 22:37:16 -05:00
# MyNewMigration.
2005-11-13 22:51:39 -05:00
#
2008-03-26 08:27:52 -04:00
# There is a special syntactic shortcut to generate migrations that add fields to a table.
2010-06-15 14:41:30 -04:00
#
2010-02-06 11:18:10 -05:00
# rails generate migration add_fieldname_to_tablename fieldname:string
2008-03-26 08:27:52 -04:00
#
2009-07-25 11:03:58 -04:00
# This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
2008-03-26 08:27:52 -04:00
# class AddFieldnameToTablename < ActiveRecord::Migration
2010-11-17 17:52:52 -05:00
# def up
2008-03-26 08:27:52 -04:00
# add_column :tablenames, :fieldname, :string
# end
2009-04-23 12:55:42 -04:00
#
2010-11-17 17:52:52 -05:00
# def down
2008-03-26 08:27:52 -04:00
# remove_column :tablenames, :fieldname
# end
# end
2009-04-23 12:55:42 -04:00
#
2005-11-13 22:51:39 -05:00
# To run migrations against the currently configured database, use
2007-09-22 14:35:41 -04:00
# <tt>rake db:migrate</tt>. This will update the database by running all of the
2008-04-09 12:20:15 -04:00
# pending migrations, creating the <tt>schema_migrations</tt> table
2009-04-23 12:55:42 -04:00
# (see "About the schema_migrations table" section below) if missing. It will also
2008-12-06 21:27:53 -05:00
# invoke the db:schema:dump task, which will update your db/schema.rb file
# to match the structure of your database.
2005-11-13 22:51:39 -05:00
#
# To roll the database back to a previous migration version, use
2007-09-22 14:35:41 -04:00
# <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
2005-11-13 22:51:39 -05:00
# you wish to downgrade. If any of the migrations throw an
2007-11-11 16:31:59 -05:00
# <tt>ActiveRecord::IrreversibleMigration</tt> exception, that step will fail and you'll
2005-11-13 22:51:39 -05:00
# have some manual work to do.
2005-07-05 03:19:20 -04:00
#
2005-07-04 14:51:02 -04:00
# == Database support
#
2005-11-13 22:51:39 -05:00
# Migrations are currently supported in MySQL, PostgreSQL, SQLite,
2006-03-17 22:02:32 -05:00
# SQL Server, Sybase, and Oracle (all supported databases except DB2).
2005-07-04 14:51:02 -04:00
#
# == More examples
#
# Not all migrations change the schema. Some just fix the data:
#
# class RemoveEmptyTags < ActiveRecord::Migration
2010-11-17 17:52:52 -05:00
# def up
2011-06-25 16:54:35 -04:00
# Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
2005-07-04 14:51:02 -04:00
# end
2005-11-13 22:51:39 -05:00
#
2010-11-17 17:52:52 -05:00
# def down
2005-07-04 14:51:02 -04:00
# # not much we can do to restore deleted data
2007-11-11 16:31:59 -05:00
# raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags"
2005-07-04 14:51:02 -04:00
# end
# end
#
# Others remove columns when they migrate up instead of down:
#
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
2010-11-17 17:52:52 -05:00
# def up
2005-07-04 14:51:02 -04:00
# remove_column :items, :incomplete_items_count
# remove_column :items, :completed_items_count
# end
#
2010-11-17 17:52:52 -05:00
# def down
2005-07-04 14:51:02 -04:00
# add_column :items, :incomplete_items_count
# add_column :items, :completed_items_count
# end
# end
2005-07-09 11:46:29 -04:00
#
2005-10-26 09:05:48 -04:00
# And sometimes you need to do something in SQL not abstracted directly by migrations:
2005-07-09 11:46:29 -04:00
#
# class MakeJoinUnique < ActiveRecord::Migration
2010-11-17 17:52:52 -05:00
# def up
2005-07-09 11:46:29 -04:00
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
# end
#
2010-11-17 17:52:52 -05:00
# def down
2005-07-09 11:46:29 -04:00
# execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`"
# end
# end
2005-09-08 13:49:31 -04:00
#
2005-11-13 22:51:39 -05:00
# == Using a model after changing its table
2005-09-08 13:49:31 -04:00
#
2010-08-14 01:13:00 -04:00
# Sometimes you'll want to add a column in a migration and populate it
# immediately after. In that case, you'll need to make a call to
# <tt>Base#reset_column_information</tt> in order to ensure that the model has the
2010-06-15 14:41:30 -04:00
# latest column data from after the new column was added. Example:
2005-09-08 13:49:31 -04:00
#
2005-11-13 22:51:39 -05:00
# class AddPeopleSalary < ActiveRecord::Migration
2010-11-17 17:54:08 -05:00
# def up
2005-09-08 13:49:31 -04:00
# add_column :people, :salary, :integer
2005-11-13 22:51:39 -05:00
# Person.reset_column_information
2011-06-25 16:54:35 -04:00
# Person.all.each do |p|
2012-08-25 21:54:55 -04:00
# p.update_attribute :salary, SalaryCalculator.compute(p)
2005-09-08 13:49:31 -04:00
# end
# end
2005-11-13 22:51:39 -05:00
# end
2006-03-04 13:46:51 -05:00
#
# == Controlling verbosity
#
# By default, migrations will describe the actions they are taking, writing
# them to the console as they happen, along with benchmarks describing how
# long each step took.
#
# You can quiet them down by setting ActiveRecord::Migration.verbose = false.
#
2008-05-25 07:29:00 -04:00
# You can also insert your own messages and benchmarks by using the +say_with_time+
2006-03-04 13:46:51 -05:00
# method:
#
2010-11-17 17:54:08 -05:00
# def up
2006-03-04 13:46:51 -05:00
# ...
# say_with_time "Updating salaries..." do
2011-06-25 16:54:35 -04:00
# Person.all.each do |p|
2012-08-25 21:54:55 -04:00
# p.update_attribute :salary, SalaryCalculator.compute(p)
2006-03-04 13:46:51 -05:00
# end
# end
# ...
# end
#
# The phrase "Updating salaries..." would then be printed, along with the
# benchmark for the block when the block completes.
2008-04-09 12:20:15 -04:00
#
# == About the schema_migrations table
#
# Rails versions 2.0 and prior used to create a table called
# <tt>schema_info</tt> when using migrations. This table contained the
# version of the schema as of the last applied migration.
#
# Starting with Rails 2.1, the <tt>schema_info</tt> table is
# (automatically) replaced by the <tt>schema_migrations</tt> table, which
# contains the version numbers of all the migrations applied.
#
# As a result, it is now possible to add migration files that are numbered
# lower than the current schema version: when migrating up, those
# never-applied "interleaved" migrations will be automatically applied, and
# when migrating down, never-applied "interleaved" migrations will be skipped.
2009-04-23 12:55:42 -04:00
#
2008-07-16 21:50:29 -04:00
# == Timestamped Migrations
#
# By default, Rails generates migrations that look like:
#
# 20080717013526_your_migration_name.rb
#
# The prefix is a generation timestamp (in UTC).
#
# If you'd prefer to use numeric prefixes, you can turn timestamped migrations
# off by setting:
#
# config.active_record.timestamped_migrations = false
2009-04-23 12:55:42 -04:00
#
2010-07-09 09:58:58 -04:00
# In application.rb.
2008-07-16 21:50:29 -04:00
#
2010-11-19 14:34:42 -05:00
# == Reversible Migrations
#
# Starting with Rails 3.1, you will be able to define reversible migrations.
# Reversible migrations are migrations that know how to go +down+ for you.
# You simply supply the +up+ logic, and the Migration system will figure out
# how to execute the down commands for you.
#
# To define a reversible migration, define the +change+ method in your
# migration like this:
#
# class TenderloveMigration < ActiveRecord::Migration
# def change
2011-12-07 10:03:51 -05:00
# create_table(:horses) do |t|
2010-11-19 14:34:42 -05:00
# t.column :content, :text
# t.column :remind_at, :datetime
# end
# end
# end
#
# This migration will create the horses table for you on the way up, and
# automatically figure out how to drop the table on the way down.
#
# Some commands like +remove_column+ cannot be reversed. If you care to
# define how to move up and down in these cases, you should define the +up+
# and +down+ methods as before.
#
# If a command cannot be reversed, an
# <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
# the migration is moving down.
#
# For a list of commands that are reversible, please see
# <tt>ActiveRecord::Migration::CommandRecorder</tt>.
2013-03-01 05:39:39 -05:00
#
# == Transactional Migrations
#
# If the database adapter supports DDL transactions, all migrations will
# automatically be wrapped in a transaction. There are queries that you
# can't execute inside a transaction though, and for these situations
# you can turn the automatic transactions off.
#
# class ChangeEnum < ActiveRecord::Migration
2013-03-08 10:35:45 -05:00
# disable_ddl_transaction!
#
2013-03-01 05:39:39 -05:00
# def up
# execute "ALTER TYPE model_size ADD VALUE 'new_value'"
# end
# end
#
# Remember that you can still open your own transactions, even if you
# are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
2005-07-04 14:51:02 -04:00
class Migration
2010-11-18 17:59:25 -05:00
autoload :CommandRecorder , 'active_record/migration/command_recorder'
2012-06-05 20:15:16 -04:00
# This class is used to verify that all migrations have been run before
# loading a web page if config.active_record.migration_error is set to :page_load
class CheckPending
def initialize ( app )
@app = app
2013-06-05 04:56:46 -04:00
@last_check = 0
2012-06-05 20:15:16 -04:00
end
def call ( env )
2013-06-05 04:56:46 -04:00
mtime = ActiveRecord :: Migrator . last_migration . mtime . to_i
if @last_check < mtime
ActiveRecord :: Migration . check_pending!
@last_check = mtime
end
2012-06-10 05:38:37 -04:00
@app . call ( env )
2012-06-05 20:15:16 -04:00
end
end
2005-03-01 09:27:32 -05:00
class << self
2010-11-17 15:53:38 -05:00
attr_accessor :delegate # :nodoc:
2013-03-01 05:39:39 -05:00
attr_accessor :disable_ddl_transaction # :nodoc:
2010-11-17 16:31:43 -05:00
2013-08-22 16:15:11 -04:00
def check_pending!
raise ActiveRecord :: PendingMigrationError if ActiveRecord :: Migrator . needs_migration?
end
2012-06-05 20:15:16 -04:00
2013-08-22 16:15:11 -04:00
def method_missing ( name , * args , & block ) # :nodoc:
( delegate || superclass . delegate ) . send ( name , * args , & block )
end
2010-11-17 16:31:43 -05:00
2013-08-22 16:15:11 -04:00
def migrate ( direction )
new . migrate direction
end
2011-08-02 23:01:38 -04:00
2013-08-22 16:15:11 -04:00
# Disable DDL transactions for this migration.
def disable_ddl_transaction!
@disable_ddl_transaction = true
end
2013-03-01 05:39:39 -05:00
end
def disable_ddl_transaction # :nodoc:
self . class . disable_ddl_transaction
end
2010-11-17 16:31:43 -05:00
2013-03-01 05:39:39 -05:00
cattr_accessor :verbose
2012-01-16 14:28:00 -05:00
attr_accessor :name , :version
2010-11-17 18:30:01 -05:00
2012-01-12 18:29:16 -05:00
def initialize ( name = self . class . name , version = nil )
@name = name
@version = version
2010-11-18 18:53:59 -05:00
@connection = nil
2010-11-17 15:53:38 -05:00
end
2013-03-01 05:39:39 -05:00
self . verbose = true
2010-11-19 13:13:56 -05:00
# instantiate the delegate object after initialize is defined
self . delegate = new
2012-08-06 22:25:01 -04:00
# Reverses the migration commands for the given block and
# the given migrations.
2012-08-06 20:44:05 -04:00
#
# The following migration will remove the table 'horses'
# and create the table 'apples' on the way up, and the reverse
# on the way down.
#
# class FixTLMigration < ActiveRecord::Migration
# def change
# revert do
# create_table(:horses) do |t|
# t.text :content
# t.datetime :remind_at
# end
# end
# create_table(:apples) do |t|
# t.string :variety
# end
# end
# end
#
2012-08-06 22:25:01 -04:00
# Or equivalently, if +TenderloveMigration+ is defined as in the
# documentation for Migration:
#
# require_relative '2012121212_tenderlove_migration'
#
# class FixupTLMigration < ActiveRecord::Migration
# def change
# revert TenderloveMigration
#
# create_table(:apples) do |t|
# t.string :variety
# end
# end
# end
2012-08-06 20:44:05 -04:00
#
2012-08-06 22:25:01 -04:00
# This command can be nested.
def revert ( * migration_classes )
run ( * migration_classes . reverse , revert : true ) unless migration_classes . empty?
if block_given?
2012-08-06 20:44:05 -04:00
if @connection . respond_to? :revert
@connection . revert { yield }
else
recorder = CommandRecorder . new ( @connection )
@connection = recorder
suppress_messages do
@connection . revert { yield }
end
@connection = recorder . delegate
recorder . commands . each do | cmd , args , block |
send ( cmd , * args , & block )
end
end
2012-08-06 22:25:01 -04:00
end
2012-01-10 08:49:44 -05:00
end
def reverting?
2012-08-06 20:44:05 -04:00
@connection . respond_to? ( :reverting ) && @connection . reverting
2012-01-10 08:49:44 -05:00
end
2013-04-04 22:06:07 -04:00
class ReversibleBlockHelper < Struct . new ( :reverting ) # :nodoc:
2012-11-11 14:43:57 -05:00
def up
yield unless reverting
end
def down
yield if reverting
end
end
# Used to specify an operation that can be run in one direction or another.
# Call the methods +up+ and +down+ of the yielded object to run a block
# only in one given direction.
# The whole block will be called in the right order within the migration.
#
# In the following example, the looping on users will always be done
# when the three columns 'first_name', 'last_name' and 'full_name' exist,
# even when migrating down:
#
# class SplitNameMigration < ActiveRecord::Migration
# def change
# add_column :users, :first_name, :string
# add_column :users, :last_name, :string
#
# reversible do |dir|
# User.reset_column_information
# User.all.each do |u|
# dir.up { u.first_name, u.last_name = u.full_name.split(' ') }
# dir.down { u.full_name = "#{u.first_name} #{u.last_name}" }
# u.save
# end
# end
#
# revert { add_column :users, :full_name, :string }
# end
# end
def reversible
helper = ReversibleBlockHelper . new ( reverting? )
2012-12-22 12:10:40 -05:00
execute_block { yield helper }
2012-11-11 14:43:57 -05:00
end
2012-08-06 22:25:01 -04:00
# Runs the given migration classes.
# Last argument can specify options:
# - :direction (default is :up)
# - :revert (default is false)
def run ( * migration_classes )
opts = migration_classes . extract_options!
dir = opts [ :direction ] || :up
dir = ( dir == :down ? :up : :down ) if opts [ :revert ]
if reverting?
# If in revert and going :up, say, we want to execute :down without reverting, so
revert { run ( * migration_classes , direction : dir , revert : true ) }
else
migration_classes . each do | migration_class |
migration_class . new . exec_migration ( @connection , dir )
end
end
end
2010-11-17 15:53:38 -05:00
def up
self . class . delegate = self
2010-11-17 16:55:03 -05:00
return unless self . class . respond_to? ( :up )
2010-11-17 15:53:38 -05:00
self . class . up
end
def down
self . class . delegate = self
2010-11-17 16:55:03 -05:00
return unless self . class . respond_to? ( :down )
2010-11-17 15:53:38 -05:00
self . class . down
end
2010-11-17 17:49:47 -05:00
# Execute this migration in the named direction
def migrate ( direction )
return unless respond_to? ( direction )
2006-03-04 13:46:51 -05:00
2010-11-17 17:49:47 -05:00
case direction
when :up then announce " migrating "
when :down then announce " reverting "
end
2006-03-04 13:46:51 -05:00
2010-11-18 18:53:59 -05:00
time = nil
ActiveRecord :: Base . connection_pool . with_connection do | conn |
2012-08-06 20:44:05 -04:00
time = Benchmark . measure do
2012-08-06 22:20:34 -04:00
exec_migration ( conn , direction )
2010-11-19 13:31:03 -05:00
end
2010-11-18 18:53:59 -05:00
end
2007-05-25 22:36:55 -04:00
2010-11-17 17:49:47 -05:00
case direction
when :up then announce " migrated (%.4fs) " % time . real ; write
when :down then announce " reverted (%.4fs) " % time . real ; write
2006-03-04 13:46:51 -05:00
end
2010-11-17 17:49:47 -05:00
end
2012-08-06 22:20:34 -04:00
def exec_migration ( conn , direction )
@connection = conn
if respond_to? ( :change )
if direction == :down
revert { change }
else
change
end
else
send ( direction )
end
ensure
@connection = nil
end
2006-03-04 13:46:51 -05:00
2010-11-17 17:49:47 -05:00
def write ( text = " " )
puts ( text ) if verbose
end
2010-03-14 20:43:59 -04:00
2010-11-17 17:49:47 -05:00
def announce ( message )
text = " #{ version } #{ name } : #{ message } "
length = [ 0 , 75 - text . length ] . max
write " == %s %s " % [ text , " = " * length ]
end
2006-03-04 13:46:51 -05:00
2010-11-17 17:49:47 -05:00
def say ( message , subitem = false )
write " #{ subitem ? " -> " : " -- " } #{ message } "
end
2006-03-04 13:46:51 -05:00
2010-11-17 17:49:47 -05:00
def say_with_time ( message )
say ( message )
result = nil
time = Benchmark . measure { result = yield }
say " %.4fs " % time . real , :subitem
say ( " #{ result } rows " , :subitem ) if result . is_a? ( Integer )
result
end
2006-03-09 13:38:39 -05:00
2010-11-17 17:49:47 -05:00
def suppress_messages
save , self . verbose = verbose , false
yield
ensure
self . verbose = save
end
2010-01-07 16:30:51 -05:00
2010-11-17 17:49:47 -05:00
def connection
2010-11-18 18:53:59 -05:00
@connection || ActiveRecord :: Base . connection
2010-11-17 17:49:47 -05:00
end
2007-05-25 22:36:55 -04:00
2010-11-17 17:49:47 -05:00
def method_missing ( method , * arguments , & block )
arg_list = arguments . map { | a | a . inspect } * ', '
say_with_time " #{ method } ( #{ arg_list } ) " do
2012-08-06 20:44:05 -04:00
unless @connection . respond_to? :revert
2012-01-10 08:49:44 -05:00
unless arguments . empty? || method == :execute
2013-08-22 16:15:11 -04:00
arguments [ 0 ] = proper_table_name ( arguments . first , table_name_options )
arguments [ 1 ] = proper_table_name ( arguments . second , table_name_options ) if method == :rename_table
2012-01-10 08:49:44 -05:00
end
2005-03-01 09:27:32 -05:00
end
2010-11-17 17:49:47 -05:00
return super unless connection . respond_to? ( method )
connection . send ( method , * arguments , & block )
2006-03-04 13:46:51 -05:00
end
2010-11-17 17:49:47 -05:00
end
2010-07-26 08:06:14 -04:00
2010-11-17 17:49:47 -05:00
def copy ( destination , sources , options = { } )
copied = [ ]
2010-07-26 08:06:14 -04:00
2010-11-17 17:49:47 -05:00
FileUtils . mkdir_p ( destination ) unless File . exists? ( destination )
2010-11-16 11:00:01 -05:00
2010-11-17 17:49:47 -05:00
destination_migrations = ActiveRecord :: Migrator . migrations ( destination )
last = destination_migrations . last
2011-12-09 06:15:54 -05:00
sources . each do | scope , path |
2010-11-17 17:49:47 -05:00
source_migrations = ActiveRecord :: Migrator . migrations ( path )
2010-07-26 08:06:14 -04:00
2010-11-17 17:49:47 -05:00
source_migrations . each do | migration |
2013-03-09 01:37:26 -05:00
source = File . binread ( migration . filename )
inserted_comment = " # This migration comes from #{ scope } (originally #{ migration . version } ) \n "
if / \ A # .* \ b(?:en)?coding: \ s* \ S+ / =~ source
# If we have a magic comment in the original migration,
# insert our comment after the first newline(end of the magic comment line)
# so the magic keep working.
# Note that magic comments must be at the first line(except sh-bang).
source [ / \ n / ] = " \n #{ inserted_comment } "
else
source = " #{ inserted_comment } #{ source } "
end
2010-10-09 04:28:46 -04:00
2010-11-17 17:49:47 -05:00
if duplicate = destination_migrations . detect { | m | m . name == migration . name }
2011-12-09 06:15:54 -05:00
if options [ :on_skip ] && duplicate . scope != scope . to_s
options [ :on_skip ] . call ( scope , migration )
2011-12-08 19:49:08 -05:00
end
2010-11-17 17:49:47 -05:00
next
end
2010-07-26 08:06:14 -04:00
2010-11-17 17:49:47 -05:00
migration . version = next_migration_number ( last ? last . version + 1 : 0 ) . to_i
2011-12-09 06:15:54 -05:00
new_path = File . join ( destination , " #{ migration . version } _ #{ migration . name . underscore } . #{ scope } .rb " )
2010-11-17 17:49:47 -05:00
old_path , migration . filename = migration . filename , new_path
last = migration
2010-07-26 08:06:14 -04:00
2013-03-09 01:37:26 -05:00
File . binwrite ( migration . filename , source )
2010-11-17 17:49:47 -05:00
copied << migration
2011-12-09 06:15:54 -05:00
options [ :on_copy ] . call ( scope , migration , old_path ) if options [ :on_copy ]
2010-11-17 17:49:47 -05:00
destination_migrations << migration
2010-07-26 08:06:14 -04:00
end
end
2010-11-17 17:49:47 -05:00
copied
end
2013-08-22 16:15:11 -04:00
# Finds the correct table name given an Active Record object.
# Uses the Active Record object's own table_name, or pre/suffix from the
# options passed in.
def proper_table_name ( name , options = { } )
if name . respond_to? :table_name
name . table_name
else
" #{ options [ :table_name_prefix ] } #{ name } #{ options [ :table_name_suffix ] } "
end
end
2013-05-12 06:22:09 -04:00
# Determines the version number of the next migration.
2010-11-17 17:49:47 -05:00
def next_migration_number ( number )
if ActiveRecord :: Base . timestamped_migrations
[ Time . now . utc . strftime ( " %Y%m%d%H%M%S " ) , " %.14d " % number ] . max
else
" %.3d " % number
2010-07-26 08:06:14 -04:00
end
2010-11-17 17:49:47 -05:00
end
2012-12-22 12:10:40 -05:00
2013-08-22 16:15:11 -04:00
def table_name_options ( config = ActiveRecord :: Base )
{
table_name_prefix : config . table_name_prefix ,
table_name_suffix : config . table_name_suffix
}
end
2012-12-22 12:10:40 -05:00
private
def execute_block
if connection . respond_to? :execute_block
super # use normal delegation to record the block
else
yield
end
end
2005-03-01 09:27:32 -05:00
end
2008-08-02 01:44:02 -04:00
# MigrationProxy is used to defer loading of the actual migration classes
# until they are needed
2011-12-09 05:45:19 -05:00
class MigrationProxy < Struct . new ( :name , :version , :filename , :scope )
2008-08-02 01:44:02 -04:00
2011-12-09 05:45:19 -05:00
def initialize ( name , version , filename , scope )
2010-10-03 19:32:27 -04:00
super
@migration = nil
end
2008-08-02 01:44:02 -04:00
2010-10-09 04:28:46 -04:00
def basename
File . basename ( filename )
end
2013-06-05 04:56:46 -04:00
def mtime
File . mtime filename
end
2013-03-01 05:39:39 -05:00
delegate :migrate , :announce , :write , :disable_ddl_transaction , to : :migration
2008-08-02 01:44:02 -04:00
private
def migration
@migration || = load_migration
end
def load_migration
2010-03-23 21:20:28 -04:00
require ( File . expand_path ( filename ) )
2010-11-17 15:53:38 -05:00
name . constantize . new
2008-08-02 01:44:02 -04:00
end
end
2013-06-05 05:20:31 -04:00
class NullMigration < MigrationProxy #:nodoc:
def initialize
2013-06-05 04:56:46 -04:00
super ( nil , 0 , nil , nil )
end
def mtime
0
end
end
2005-03-22 08:09:44 -05:00
class Migrator #:nodoc:
2005-03-01 09:27:32 -05:00
class << self
2010-12-03 07:12:59 -05:00
attr_writer :migrations_paths
alias :migrations_path = :migrations_paths =
2010-07-25 13:04:32 -04:00
2011-12-09 14:07:29 -05:00
def migrate ( migrations_paths , target_version = nil , & block )
2005-07-09 11:46:29 -04:00
case
2012-01-11 14:41:27 -05:00
when target_version . nil?
up ( migrations_paths , target_version , & block )
when current_version == 0 && target_version == 0
[ ]
when current_version > target_version
down ( migrations_paths , target_version , & block )
else
up ( migrations_paths , target_version , & block )
2005-07-09 11:46:29 -04:00
end
end
2008-04-09 12:20:15 -04:00
2010-12-03 07:12:59 -05:00
def rollback ( migrations_paths , steps = 1 )
move ( :down , migrations_paths , steps )
2008-03-28 17:21:01 -04:00
end
2007-05-25 22:36:55 -04:00
2010-12-03 07:12:59 -05:00
def forward ( migrations_paths , steps = 1 )
move ( :up , migrations_paths , steps )
2009-08-08 12:39:31 -04:00
end
2012-01-13 14:44:56 -05:00
def up ( migrations_paths , target_version = nil )
migrations = migrations ( migrations_paths )
migrations . select! { | m | yield m } if block_given?
self . new ( :up , migrations , target_version ) . migrate
2005-03-01 09:27:32 -05:00
end
2007-05-25 22:36:55 -04:00
2011-12-09 14:07:29 -05:00
def down ( migrations_paths , target_version = nil , & block )
2012-01-13 14:44:56 -05:00
migrations = migrations ( migrations_paths )
migrations . select! { | m | yield m } if block_given?
self . new ( :down , migrations , target_version ) . migrate
2005-03-01 09:27:32 -05:00
end
2009-04-23 12:55:42 -04:00
2010-12-03 07:12:59 -05:00
def run ( direction , migrations_paths , target_version )
2012-01-11 14:41:27 -05:00
self . new ( direction , migrations ( migrations_paths ) , target_version ) . run
end
def open ( migrations_paths )
self . new ( :up , migrations ( migrations_paths ) , nil )
2008-03-28 17:21:01 -04:00
end
2007-05-25 22:36:55 -04:00
2008-04-09 12:20:15 -04:00
def schema_migrations_table_name
2012-01-11 18:24:15 -05:00
SchemaMigration . table_name
2005-09-26 17:30:12 -04:00
end
2008-08-26 05:57:33 -04:00
def get_all_versions
2012-01-11 18:24:15 -05:00
SchemaMigration . all . map { | x | x . version . to_i } . sort
2008-08-26 05:57:33 -04:00
end
2005-03-01 09:27:32 -05:00
def current_version
2008-08-26 02:14:12 -04:00
sm_table = schema_migrations_table_name
if Base . connection . table_exists? ( sm_table )
2008-08-26 05:57:33 -04:00
get_all_versions . max || 0
2008-08-26 02:14:12 -04:00
else
0
end
2005-03-01 09:27:32 -05:00
end
2005-09-26 17:30:12 -04:00
2012-06-10 06:44:19 -04:00
def needs_migration?
2012-06-05 20:15:16 -04:00
current_version < last_version
2012-06-03 16:07:11 -04:00
end
def last_version
2013-06-05 04:56:46 -04:00
last_migration . version
end
2013-06-05 05:20:31 -04:00
def last_migration #:nodoc:
2013-06-05 04:56:46 -04:00
migrations ( migrations_paths ) . last || NullMigration . new
2012-06-03 16:07:11 -04:00
end
2013-08-22 16:15:11 -04:00
def proper_table_name ( name , options = { } )
2013-08-24 23:33:56 -04:00
ActiveSupport :: Deprecation . warn " ActiveRecord::Migrator.proper_table_name is deprecated and will be removed in Rails 4.2. Use the proper_table_name instance method on ActiveRecord::Migration instead "
2013-08-22 16:15:11 -04:00
options = {
table_name_prefix : ActiveRecord :: Base . table_name_prefix ,
table_name_suffix : ActiveRecord :: Base . table_name_suffix
} . merge ( options )
2012-11-05 23:44:59 -05:00
if name . respond_to? :table_name
name . table_name
else
2013-08-22 16:15:11 -04:00
" #{ options [ :table_name_prefix ] } #{ name } #{ options [ :table_name_suffix ] } "
2012-11-05 23:44:59 -05:00
end
2005-09-26 17:30:12 -04:00
end
2009-08-08 15:47:14 -04:00
2010-12-03 07:12:59 -05:00
def migrations_paths
@migrations_paths || = [ 'db/migrate' ]
# just to not break things if someone uses: migration_path = some_string
2012-01-05 22:53:29 -05:00
Array ( @migrations_paths )
2010-12-03 07:12:59 -05:00
end
2010-07-25 13:04:32 -04:00
def migrations_path
2010-12-03 07:12:59 -05:00
migrations_paths . first
2010-07-25 13:04:32 -04:00
end
2012-01-10 17:02:21 -05:00
def migrations ( paths )
2012-01-05 22:53:29 -05:00
paths = Array ( paths )
2010-12-03 07:12:59 -05:00
2012-01-10 17:02:21 -05:00
files = Dir [ * paths . map { | p | " #{ p } /**/[0-9]*_*.rb " } ]
2010-07-26 08:06:14 -04:00
2010-10-03 19:41:59 -04:00
migrations = files . map do | file |
2012-12-12 15:51:38 -05:00
version , name , scope = file . scan ( / ([0-9]+)_([_a-z0-9]*) \ .?([_a-z0-9]*)? \ .rb \ z / ) . first
2010-07-26 08:06:14 -04:00
raise IllegalMigrationNameError . new ( file ) unless version
version = version . to_i
2010-10-03 19:41:59 -04:00
name = name . camelize
2010-07-26 08:06:14 -04:00
2011-12-09 05:45:19 -05:00
MigrationProxy . new ( name , version , file , scope )
2010-07-26 08:06:14 -04:00
end
migrations . sort_by ( & :version )
end
2009-08-08 15:47:14 -04:00
private
2010-12-03 07:12:59 -05:00
def move ( direction , migrations_paths , steps )
2012-01-11 14:41:27 -05:00
migrator = self . new ( direction , migrations ( migrations_paths ) )
2009-08-08 15:47:14 -04:00
start_index = migrator . migrations . index ( migrator . current_migration )
if start_index
finish = migrator . migrations [ start_index + steps ]
version = finish ? finish . version : 0
2010-12-03 07:12:59 -05:00
send ( direction , migrations_paths , version )
2009-08-08 15:47:14 -04:00
end
end
2005-03-01 09:27:32 -05:00
end
2007-05-25 22:36:55 -04:00
2012-01-11 14:41:27 -05:00
def initialize ( direction , migrations , target_version = nil )
2005-07-04 14:51:02 -04:00
raise StandardError . new ( " This database does not yet support migrations " ) unless Base . connection . supports_migrations?
2012-01-11 14:41:27 -05:00
2012-01-13 16:34:54 -05:00
@direction = direction
@target_version = target_version
@migrated_versions = nil
2013-07-04 09:04:31 -04:00
@migrations = migrations
2012-01-11 14:41:27 -05:00
2012-01-12 18:29:16 -05:00
validate ( @migrations )
2012-01-13 18:52:19 -05:00
ActiveRecord :: SchemaMigration . create_table
2005-03-01 09:27:32 -05:00
end
def current_version
2013-03-19 22:09:17 -04:00
migrated . max || 0
2005-03-01 09:27:32 -05:00
end
2009-04-23 12:55:42 -04:00
2008-03-28 17:21:01 -04:00
def current_migration
migrations . detect { | m | m . version == current_version }
end
2012-01-13 16:34:54 -05:00
alias :current :current_migration
2009-04-23 12:55:42 -04:00
2008-03-28 17:21:01 -04:00
def run
2013-02-25 10:05:22 -05:00
migration = migrations . detect { | m | m . version == @target_version }
raise UnknownMigrationVersionError . new ( @target_version ) if migration . nil?
unless ( up? && migrated . include? ( migration . version . to_i ) ) || ( down? && ! migrated . include? ( migration . version . to_i ) )
begin
2013-04-24 13:08:44 -04:00
execute_migration_in_transaction ( migration , @direction )
2013-02-25 10:05:22 -05:00
rescue = > e
2013-04-19 10:22:32 -04:00
canceled_msg = use_transaction? ( migration ) ? " , this migration was canceled " : " "
2013-02-25 10:05:22 -05:00
raise StandardError , " An error has occurred #{ canceled_msg } : \n \n #{ e } " , e . backtrace
end
2008-06-13 10:14:07 -04:00
end
2008-03-28 17:21:01 -04:00
end
2005-03-01 09:27:32 -05:00
2012-01-13 14:44:56 -05:00
def migrate
2012-01-13 14:34:12 -05:00
if ! target && @target_version && @target_version > 0
2008-03-28 17:21:01 -04:00
raise UnknownMigrationVersionError . new ( @target_version )
end
2009-04-23 12:55:42 -04:00
2013-07-04 04:02:20 -04:00
runnable . each do | migration |
2009-10-27 19:30:24 -04:00
Base . logger . info " Migrating to #{ migration . name } ( #{ migration . version } ) " if Base . logger
2008-04-09 12:20:15 -04:00
2008-08-22 16:53:31 -04:00
begin
2013-04-24 13:08:44 -04:00
execute_migration_in_transaction ( migration , @direction )
2008-08-22 16:53:31 -04:00
rescue = > e
2013-03-01 05:39:39 -05:00
canceled_msg = use_transaction? ( migration ) ? " this and " : " "
2008-08-22 16:53:31 -04:00
raise StandardError , " An error has occurred, #{ canceled_msg } all later migrations canceled: \n \n #{ e } " , e . backtrace
2008-04-09 12:20:15 -04:00
end
2008-03-28 17:21:01 -04:00
end
2012-01-13 14:34:12 -05:00
end
def runnable
runnable = migrations [ start .. finish ]
if up?
runnable . reject { | m | ran? ( m ) }
else
# skip the last migration if we're headed down, but not ALL the way down
runnable . pop if target
runnable . find_all { | m | ran? ( m ) }
end
2008-03-28 17:21:01 -04:00
end
2005-03-01 09:27:32 -05:00
2008-03-28 17:21:01 -04:00
def migrations
2012-01-13 16:34:54 -05:00
down? ? @migrations . reverse : @migrations . sort_by ( & :version )
2005-03-01 09:27:32 -05:00
end
2007-12-06 13:57:19 -05:00
def pending_migrations
2008-04-09 12:20:15 -04:00
already_migrated = migrated
2012-01-13 16:34:54 -05:00
migrations . reject { | m | already_migrated . include? ( m . version ) }
2008-04-09 12:20:15 -04:00
end
def migrated
2012-01-13 16:34:54 -05:00
@migrated_versions || = Set . new ( self . class . get_all_versions )
2007-12-06 13:57:19 -05:00
end
2005-03-01 09:27:32 -05:00
private
2012-01-13 14:34:12 -05:00
def ran? ( migration )
migrated . include? ( migration . version . to_i )
end
2013-04-24 13:08:44 -04:00
def execute_migration_in_transaction ( migration , direction )
ddl_transaction ( migration ) do
migration . migrate ( direction )
record_version_state_after_migrating ( migration . version )
end
end
2012-01-13 14:34:12 -05:00
def target
migrations . detect { | m | m . version == @target_version }
end
def finish
migrations . index ( target ) || migrations . size - 1
end
def start
up? ? 0 : ( migrations . index ( current ) || 0 )
end
2012-01-12 18:29:16 -05:00
def validate ( migrations )
name , = migrations . group_by ( & :name ) . find { | _ , v | v . length > 1 }
raise DuplicateMigrationNameError . new ( name ) if name
2007-05-25 22:36:55 -04:00
2012-01-12 18:29:16 -05:00
version , = migrations . group_by ( & :version ) . find { | _ , v | v . length > 1 }
raise DuplicateMigrationVersionError . new ( version ) if version
end
2012-12-09 17:52:28 -05:00
def record_version_state_after_migrating ( version )
2012-01-12 18:29:16 -05:00
if down?
2012-12-09 17:52:28 -05:00
migrated . delete ( version )
ActiveRecord :: SchemaMigration . where ( :version = > version . to_s ) . delete_all
2012-01-12 18:29:16 -05:00
else
2012-12-09 17:52:28 -05:00
migrated << version
ActiveRecord :: SchemaMigration . create! ( :version = > version . to_s )
2005-03-01 09:27:32 -05:00
end
2012-01-12 18:29:16 -05:00
end
2008-08-22 16:53:31 -04:00
2012-01-12 18:29:16 -05:00
def up?
@direction == :up
end
def down?
@direction == :down
end
# Wrap the migration in a transaction only if supported by the adapter.
2013-03-01 05:39:39 -05:00
def ddl_transaction ( migration )
if use_transaction? ( migration )
2012-01-13 16:34:54 -05:00
Base . transaction { yield }
2012-01-12 18:29:16 -05:00
else
2012-01-13 16:34:54 -05:00
yield
2008-08-22 16:53:31 -04:00
end
2012-01-12 18:29:16 -05:00
end
2013-03-01 05:39:39 -05:00
def use_transaction? ( migration )
! migration . disable_ddl_transaction && Base . connection . supports_ddl_transactions?
end
2005-03-01 09:27:32 -05:00
end
2005-06-07 13:00:43 -04:00
end