2
class IrreversibleMigration < ActiveRecordError#:nodoc:
5
class DuplicateMigrationVersionError < ActiveRecordError#:nodoc:
6
def initialize(version)
7
super("Multiple migrations have the version number #{version}")
11
class DuplicateMigrationNameError < ActiveRecordError#:nodoc:
13
super("Multiple migrations have the name #{name}")
17
class UnknownMigrationVersionError < ActiveRecordError #:nodoc:
18
def initialize(version)
19
super("No migration with version number #{version}")
23
class IllegalMigrationNameError < ActiveRecordError#:nodoc:
25
super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed)")
29
# Migrations can manage the evolution of a schema used by several physical databases. It's a solution
30
# to the common problem of adding a field to make a new feature work in your local database, but being unsure of how to
31
# push that change to other developers and to the production server. With migrations, you can describe the transformations
32
# in self-contained classes that can be checked into version control systems and executed against another database that
33
# might be one, two, or five versions behind.
35
# Example of a simple migration:
37
# class AddSsl < ActiveRecord::Migration
39
# add_column :accounts, :ssl_enabled, :boolean, :default => 1
43
# remove_column :accounts, :ssl_enabled
47
# This migration will add a boolean flag to the accounts table and remove it if you're backing out of the migration.
48
# It shows how all migrations have two class methods +up+ and +down+ that describes the transformations required to implement
49
# or remove the migration. These methods can consist of both the migration specific methods like add_column and remove_column,
50
# but may also contain regular Ruby code for generating data needed for the transformations.
52
# Example of a more complex migration that also needs to initialize data:
54
# class AddSystemSettings < ActiveRecord::Migration
56
# create_table :system_settings do |t|
64
# SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
68
# drop_table :system_settings
72
# This migration first adds the system_settings table, then creates the very first row in it using the Active Record model
73
# that relies on the table. It also uses the more advanced create_table syntax where you can specify a complete table schema
76
# == Available transformations
78
# * <tt>create_table(name, options)</tt> Creates a table called +name+ and makes the table object available to a block
79
# that can then add columns to it, following the same format as add_column. See example above. The options hash is for
80
# fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create table definition.
81
# * <tt>drop_table(name)</tt>: Drops the table called +name+.
82
# * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+ to +new_name+.
83
# * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column to the table called +table_name+
84
# named +column_name+ specified to be one of the following types:
85
# <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>, <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
86
# <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be specified by passing an
87
# +options+ hash like <tt>{ :default => 11 }</tt>. Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g. <tt>{ :limit => 50, :null => false }</tt>)
88
# -- see ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
89
# * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames a column but keeps the type and content.
90
# * <tt>change_column(table_name, column_name, type, options)</tt>: Changes the column to a different type using the same
91
# parameters as add_column.
92
# * <tt>remove_column(table_name, column_name)</tt>: Removes the column named +column_name+ from the table called +table_name+.
93
# * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index with the name of the column. Other options include
94
# <tt>:name</tt> and <tt>:unique</tt> (e.g. <tt>{ :name => "users_name_index", :unique => true }</tt>).
95
# * <tt>remove_index(table_name, index_name)</tt>: Removes the index specified by +index_name+.
97
# == Irreversible transformations
99
# Some transformations are destructive in a manner that cannot be reversed. Migrations of that kind should raise
100
# an <tt>ActiveRecord::IrreversibleMigration</tt> exception in their +down+ method.
102
# == Running migrations from within Rails
104
# The Rails package has several tools to help create and apply migrations.
106
# To generate a new migration, you can use
107
# script/generate migration MyNewMigration
109
# where MyNewMigration is the name of your migration. The generator will
110
# create an empty migration file <tt>nnn_my_new_migration.rb</tt> in the <tt>db/migrate/</tt>
111
# directory where <tt>nnn</tt> is the next largest migration number.
113
# You may then edit the <tt>self.up</tt> and <tt>self.down</tt> methods of
116
# There is a special syntactic shortcut to generate migrations that add fields to a table.
117
# script/generate migration add_fieldname_to_tablename fieldname:string
119
# This will generate the file <tt>nnn_add_fieldname_to_tablename</tt>, which will look like this:
120
# class AddFieldnameToTablename < ActiveRecord::Migration
122
# add_column :tablenames, :fieldname, :string
126
# remove_column :tablenames, :fieldname
130
# To run migrations against the currently configured database, use
131
# <tt>rake db:migrate</tt>. This will update the database by running all of the
132
# pending migrations, creating the <tt>schema_migrations</tt> table
133
# (see "About the schema_migrations table" section below) if missing. It will also
134
# invoke the db:schema:dump task, which will update your db/schema.rb file
135
# to match the structure of your database.
137
# To roll the database back to a previous migration version, use
138
# <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
139
# you wish to downgrade. If any of the migrations throw an
140
# <tt>ActiveRecord::IrreversibleMigration</tt> exception, that step will fail and you'll
141
# have some manual work to do.
143
# == Database support
145
# Migrations are currently supported in MySQL, PostgreSQL, SQLite,
146
# SQL Server, Sybase, and Oracle (all supported databases except DB2).
150
# Not all migrations change the schema. Some just fix the data:
152
# class RemoveEmptyTags < ActiveRecord::Migration
154
# Tag.find(:all).each { |tag| tag.destroy if tag.pages.empty? }
158
# # not much we can do to restore deleted data
159
# raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags"
163
# Others remove columns when they migrate up instead of down:
165
# class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
167
# remove_column :items, :incomplete_items_count
168
# remove_column :items, :completed_items_count
172
# add_column :items, :incomplete_items_count
173
# add_column :items, :completed_items_count
177
# And sometimes you need to do something in SQL not abstracted directly by migrations:
179
# class MakeJoinUnique < ActiveRecord::Migration
181
# execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
185
# execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`"
189
# == Using a model after changing its table
191
# Sometimes you'll want to add a column in a migration and populate it immediately after. In that case, you'll need
192
# to make a call to Base#reset_column_information in order to ensure that the model has the latest column data from
193
# after the new column was added. Example:
195
# class AddPeopleSalary < ActiveRecord::Migration
197
# add_column :people, :salary, :integer
198
# Person.reset_column_information
199
# Person.find(:all).each do |p|
200
# p.update_attribute :salary, SalaryCalculator.compute(p)
205
# == Controlling verbosity
207
# By default, migrations will describe the actions they are taking, writing
208
# them to the console as they happen, along with benchmarks describing how
209
# long each step took.
211
# You can quiet them down by setting ActiveRecord::Migration.verbose = false.
213
# You can also insert your own messages and benchmarks by using the +say_with_time+
218
# say_with_time "Updating salaries..." do
219
# Person.find(:all).each do |p|
220
# p.update_attribute :salary, SalaryCalculator.compute(p)
226
# The phrase "Updating salaries..." would then be printed, along with the
227
# benchmark for the block when the block completes.
229
# == About the schema_migrations table
231
# Rails versions 2.0 and prior used to create a table called
232
# <tt>schema_info</tt> when using migrations. This table contained the
233
# version of the schema as of the last applied migration.
235
# Starting with Rails 2.1, the <tt>schema_info</tt> table is
236
# (automatically) replaced by the <tt>schema_migrations</tt> table, which
237
# contains the version numbers of all the migrations applied.
239
# As a result, it is now possible to add migration files that are numbered
240
# lower than the current schema version: when migrating up, those
241
# never-applied "interleaved" migrations will be automatically applied, and
242
# when migrating down, never-applied "interleaved" migrations will be skipped.
244
# == Timestamped Migrations
246
# By default, Rails generates migrations that look like:
248
# 20080717013526_your_migration_name.rb
250
# The prefix is a generation timestamp (in UTC).
252
# If you'd prefer to use numeric prefixes, you can turn timestamped migrations
255
# config.active_record.timestamped_migrations = false
261
cattr_accessor :verbose
264
def up_with_benchmarks #:nodoc:
268
def down_with_benchmarks #:nodoc:
272
# Execute this migration in the named direction
273
def migrate(direction)
274
return unless respond_to?(direction)
277
when :up then announce "migrating"
278
when :down then announce "reverting"
282
time = Benchmark.measure { result = send("#{direction}_without_benchmarks") }
285
when :up then announce "migrated (%.4fs)" % time.real; write
286
when :down then announce "reverted (%.4fs)" % time.real; write
292
# Because the method added may do an alias_method, it can be invoked
293
# recursively. We use @ignore_new_methods as a guard to indicate whether
294
# it is safe for the call to proceed.
295
def singleton_method_added(sym) #:nodoc:
296
return if defined?(@ignore_new_methods) && @ignore_new_methods
299
@ignore_new_methods = true
303
klass = (class << self; self; end)
304
klass.send(:alias_method_chain, sym, "benchmarks")
307
@ignore_new_methods = false
312
puts(text) if verbose
315
def announce(message)
316
text = "#{@version} #{name}: #{message}"
317
length = [0, 75 - text.length].max
318
write "== %s %s" % [text, "=" * length]
321
def say(message, subitem=false)
322
write "#{subitem ? " ->" : "--"} #{message}"
325
def say_with_time(message)
328
time = Benchmark.measure { result = yield }
329
say "%.4fs" % time.real, :subitem
330
say("#{result} rows", :subitem) if result.is_a?(Integer)
334
def suppress_messages
335
save, self.verbose = verbose, false
342
ActiveRecord::Base.connection
345
def method_missing(method, *arguments, &block)
346
arg_list = arguments.map(&:inspect) * ', '
348
say_with_time "#{method}(#{arg_list})" do
349
unless arguments.empty? || method == :execute
350
arguments[0] = Migrator.proper_table_name(arguments.first)
352
connection.send(method, *arguments, &block)
358
# MigrationProxy is used to defer loading of the actual migration classes
359
# until they are needed
362
attr_accessor :name, :version, :filename
364
delegate :migrate, :announce, :write, :to=>:migration
369
@migration ||= load_migration
379
class Migrator#:nodoc:
381
def migrate(migrations_path, target_version = nil)
383
when target_version.nil? then up(migrations_path, target_version)
384
when current_version > target_version then down(migrations_path, target_version)
385
else up(migrations_path, target_version)
389
def rollback(migrations_path, steps=1)
390
migrator = self.new(:down, migrations_path)
391
start_index = migrator.migrations.index(migrator.current_migration)
393
return unless start_index
395
finish = migrator.migrations[start_index + steps]
396
down(migrations_path, finish ? finish.version : 0)
399
def up(migrations_path, target_version = nil)
400
self.new(:up, migrations_path, target_version).migrate
403
def down(migrations_path, target_version = nil)
404
self.new(:down, migrations_path, target_version).migrate
407
def run(direction, migrations_path, target_version)
408
self.new(direction, migrations_path, target_version).run
411
def schema_migrations_table_name
412
Base.table_name_prefix + 'schema_migrations' + Base.table_name_suffix
416
Base.connection.select_values("SELECT version FROM #{schema_migrations_table_name}").map(&:to_i).sort
420
sm_table = schema_migrations_table_name
421
if Base.connection.table_exists?(sm_table)
422
get_all_versions.max || 0
428
def proper_table_name(name)
429
# Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string
430
name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}"
434
def initialize(direction, migrations_path, target_version = nil)
435
raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
436
Base.connection.initialize_schema_migrations_table
437
@direction, @migrations_path, @target_version = direction, migrations_path, target_version
444
def current_migration
445
migrations.detect { |m| m.version == current_version }
449
target = migrations.detect { |m| m.version == @target_version }
450
raise UnknownMigrationVersionError.new(@target_version) if target.nil?
451
unless (up? && migrated.include?(target.version.to_i)) || (down? && !migrated.include?(target.version.to_i))
452
target.migrate(@direction)
453
record_version_state_after_migrating(target.version)
458
current = migrations.detect { |m| m.version == current_version }
459
target = migrations.detect { |m| m.version == @target_version }
461
if target.nil? && !@target_version.nil? && @target_version > 0
462
raise UnknownMigrationVersionError.new(@target_version)
465
start = up? ? 0 : (migrations.index(current) || 0)
466
finish = migrations.index(target) || migrations.size - 1
467
runnable = migrations[start..finish]
469
# skip the last migration if we're headed down, but not ALL the way down
470
runnable.pop if down? && !target.nil?
472
runnable.each do |migration|
473
Base.logger.info "Migrating to #{migration.name} (#{migration.version})"
475
# On our way up, we skip migrating the ones we've already migrated
476
next if up? && migrated.include?(migration.version.to_i)
478
# On our way down, we skip reverting the ones we've never migrated
479
if down? && !migrated.include?(migration.version.to_i)
480
migration.announce 'never migrated, skipping'; migration.write
486
migration.migrate(@direction)
487
record_version_state_after_migrating(migration.version)
490
canceled_msg = Base.connection.supports_ddl_transactions? ? "this and " : ""
491
raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
497
@migrations ||= begin
498
files = Dir["#{@migrations_path}/[0-9]*_*.rb"]
500
migrations = files.inject([]) do |klasses, file|
501
version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
503
raise IllegalMigrationNameError.new(file) unless version
504
version = version.to_i
506
if klasses.detect { |m| m.version == version }
507
raise DuplicateMigrationVersionError.new(version)
510
if klasses.detect { |m| m.name == name.camelize }
511
raise DuplicateMigrationNameError.new(name.camelize)
514
klasses << returning(MigrationProxy.new) do |migration|
515
migration.name = name.camelize
516
migration.version = version
517
migration.filename = file
521
migrations = migrations.sort_by(&:version)
522
down? ? migrations.reverse : migrations
526
def pending_migrations
527
already_migrated = migrated
528
migrations.reject { |m| already_migrated.include?(m.version.to_i) }
532
@migrated_versions ||= self.class.get_all_versions
536
def record_version_state_after_migrating(version)
537
sm_table = self.class.schema_migrations_table_name
539
@migrated_versions ||= []
541
@migrated_versions.delete(version.to_i)
542
Base.connection.update("DELETE FROM #{sm_table} WHERE version = '#{version}'")
544
@migrated_versions.push(version.to_i).sort!
545
Base.connection.insert("INSERT INTO #{sm_table} (version) VALUES ('#{version}')")
557
# Wrap the migration in a transaction only if supported by the adapter.
558
def ddl_transaction(&block)
559
if Base.connection.supports_ddl_transactions?
560
Base.transaction { block.call }