657acd6dc090223daadfd8c7de11394ec6443ef7
[feedcatcher.git] / vendor / rails / activerecord / lib / active_record / migration.rb
1 module ActiveRecord
2 class IrreversibleMigration < ActiveRecordError#:nodoc:
3 end
4
5 class DuplicateMigrationVersionError < ActiveRecordError#:nodoc:
6 def initialize(version)
7 super("Multiple migrations have the version number #{version}")
8 end
9 end
10
11 class DuplicateMigrationNameError < ActiveRecordError#:nodoc:
12 def initialize(name)
13 super("Multiple migrations have the name #{name}")
14 end
15 end
16
17 class UnknownMigrationVersionError < ActiveRecordError #:nodoc:
18 def initialize(version)
19 super("No migration with version number #{version}")
20 end
21 end
22
23 class IllegalMigrationNameError < ActiveRecordError#:nodoc:
24 def initialize(name)
25 super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed)")
26 end
27 end
28
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.
34 #
35 # Example of a simple migration:
36 #
37 # class AddSsl < ActiveRecord::Migration
38 # def self.up
39 # add_column :accounts, :ssl_enabled, :boolean, :default => 1
40 # end
41 #
42 # def self.down
43 # remove_column :accounts, :ssl_enabled
44 # end
45 # end
46 #
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.
51 #
52 # Example of a more complex migration that also needs to initialize data:
53 #
54 # class AddSystemSettings < ActiveRecord::Migration
55 # def self.up
56 # create_table :system_settings do |t|
57 # t.string :name
58 # t.string :label
59 # t.text :value
60 # t.string :type
61 # t.integer :position
62 # end
63 #
64 # SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1
65 # end
66 #
67 # def self.down
68 # drop_table :system_settings
69 # end
70 # end
71 #
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
74 # in one block call.
75 #
76 # == Available transformations
77 #
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+.
96 #
97 # == Irreversible transformations
98 #
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.
101 #
102 # == Running migrations from within Rails
103 #
104 # The Rails package has several tools to help create and apply migrations.
105 #
106 # To generate a new migration, you can use
107 # script/generate migration MyNewMigration
108 #
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.
112 #
113 # You may then edit the <tt>self.up</tt> and <tt>self.down</tt> methods of
114 # MyNewMigration.
115 #
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
118 #
119 # This will generate the file <tt>nnn_add_fieldname_to_tablename</tt>, which will look like this:
120 # class AddFieldnameToTablename < ActiveRecord::Migration
121 # def self.up
122 # add_column :tablenames, :fieldname, :string
123 # end
124 #
125 # def self.down
126 # remove_column :tablenames, :fieldname
127 # end
128 # end
129 #
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.
136 #
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.
142 #
143 # == Database support
144 #
145 # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
146 # SQL Server, Sybase, and Oracle (all supported databases except DB2).
147 #
148 # == More examples
149 #
150 # Not all migrations change the schema. Some just fix the data:
151 #
152 # class RemoveEmptyTags < ActiveRecord::Migration
153 # def self.up
154 # Tag.find(:all).each { |tag| tag.destroy if tag.pages.empty? }
155 # end
156 #
157 # def self.down
158 # # not much we can do to restore deleted data
159 # raise ActiveRecord::IrreversibleMigration, "Can't recover the deleted tags"
160 # end
161 # end
162 #
163 # Others remove columns when they migrate up instead of down:
164 #
165 # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
166 # def self.up
167 # remove_column :items, :incomplete_items_count
168 # remove_column :items, :completed_items_count
169 # end
170 #
171 # def self.down
172 # add_column :items, :incomplete_items_count
173 # add_column :items, :completed_items_count
174 # end
175 # end
176 #
177 # And sometimes you need to do something in SQL not abstracted directly by migrations:
178 #
179 # class MakeJoinUnique < ActiveRecord::Migration
180 # def self.up
181 # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
182 # end
183 #
184 # def self.down
185 # execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`"
186 # end
187 # end
188 #
189 # == Using a model after changing its table
190 #
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:
194 #
195 # class AddPeopleSalary < ActiveRecord::Migration
196 # def self.up
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)
201 # end
202 # end
203 # end
204 #
205 # == Controlling verbosity
206 #
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.
210 #
211 # You can quiet them down by setting ActiveRecord::Migration.verbose = false.
212 #
213 # You can also insert your own messages and benchmarks by using the +say_with_time+
214 # method:
215 #
216 # def self.up
217 # ...
218 # say_with_time "Updating salaries..." do
219 # Person.find(:all).each do |p|
220 # p.update_attribute :salary, SalaryCalculator.compute(p)
221 # end
222 # end
223 # ...
224 # end
225 #
226 # The phrase "Updating salaries..." would then be printed, along with the
227 # benchmark for the block when the block completes.
228 #
229 # == About the schema_migrations table
230 #
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.
234 #
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.
238 #
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.
243 #
244 # == Timestamped Migrations
245 #
246 # By default, Rails generates migrations that look like:
247 #
248 # 20080717013526_your_migration_name.rb
249 #
250 # The prefix is a generation timestamp (in UTC).
251 #
252 # If you'd prefer to use numeric prefixes, you can turn timestamped migrations
253 # off by setting:
254 #
255 # config.active_record.timestamped_migrations = false
256 #
257 # In environment.rb.
258 #
259 class Migration
260 @@verbose = true
261 cattr_accessor :verbose
262
263 class << self
264 def up_with_benchmarks #:nodoc:
265 migrate(:up)
266 end
267
268 def down_with_benchmarks #:nodoc:
269 migrate(:down)
270 end
271
272 # Execute this migration in the named direction
273 def migrate(direction)
274 return unless respond_to?(direction)
275
276 case direction
277 when :up then announce "migrating"
278 when :down then announce "reverting"
279 end
280
281 result = nil
282 time = Benchmark.measure { result = send("#{direction}_without_benchmarks") }
283
284 case direction
285 when :up then announce "migrated (%.4fs)" % time.real; write
286 when :down then announce "reverted (%.4fs)" % time.real; write
287 end
288
289 result
290 end
291
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
297
298 begin
299 @ignore_new_methods = true
300
301 case sym
302 when :up, :down
303 klass = (class << self; self; end)
304 klass.send(:alias_method_chain, sym, "benchmarks")
305 end
306 ensure
307 @ignore_new_methods = false
308 end
309 end
310
311 def write(text="")
312 puts(text) if verbose
313 end
314
315 def announce(message)
316 text = "#{@version} #{name}: #{message}"
317 length = [0, 75 - text.length].max
318 write "== %s %s" % [text, "=" * length]
319 end
320
321 def say(message, subitem=false)
322 write "#{subitem ? " ->" : "--"} #{message}"
323 end
324
325 def say_with_time(message)
326 say(message)
327 result = nil
328 time = Benchmark.measure { result = yield }
329 say "%.4fs" % time.real, :subitem
330 say("#{result} rows", :subitem) if result.is_a?(Integer)
331 result
332 end
333
334 def suppress_messages
335 save, self.verbose = verbose, false
336 yield
337 ensure
338 self.verbose = save
339 end
340
341 def connection
342 ActiveRecord::Base.connection
343 end
344
345 def method_missing(method, *arguments, &block)
346 arg_list = arguments.map(&:inspect) * ', '
347
348 say_with_time "#{method}(#{arg_list})" do
349 unless arguments.empty? || method == :execute
350 arguments[0] = Migrator.proper_table_name(arguments.first)
351 end
352 connection.send(method, *arguments, &block)
353 end
354 end
355 end
356 end
357
358 # MigrationProxy is used to defer loading of the actual migration classes
359 # until they are needed
360 class MigrationProxy
361
362 attr_accessor :name, :version, :filename
363
364 delegate :migrate, :announce, :write, :to=>:migration
365
366 private
367
368 def migration
369 @migration ||= load_migration
370 end
371
372 def load_migration
373 load(filename)
374 name.constantize
375 end
376
377 end
378
379 class Migrator#:nodoc:
380 class << self
381 def migrate(migrations_path, target_version = nil)
382 case
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)
386 end
387 end
388
389 def rollback(migrations_path, steps=1)
390 migrator = self.new(:down, migrations_path)
391 start_index = migrator.migrations.index(migrator.current_migration)
392
393 return unless start_index
394
395 finish = migrator.migrations[start_index + steps]
396 down(migrations_path, finish ? finish.version : 0)
397 end
398
399 def up(migrations_path, target_version = nil)
400 self.new(:up, migrations_path, target_version).migrate
401 end
402
403 def down(migrations_path, target_version = nil)
404 self.new(:down, migrations_path, target_version).migrate
405 end
406
407 def run(direction, migrations_path, target_version)
408 self.new(direction, migrations_path, target_version).run
409 end
410
411 def schema_migrations_table_name
412 Base.table_name_prefix + 'schema_migrations' + Base.table_name_suffix
413 end
414
415 def get_all_versions
416 Base.connection.select_values("SELECT version FROM #{schema_migrations_table_name}").map(&:to_i).sort
417 end
418
419 def current_version
420 sm_table = schema_migrations_table_name
421 if Base.connection.table_exists?(sm_table)
422 get_all_versions.max || 0
423 else
424 0
425 end
426 end
427
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}"
431 end
432 end
433
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
438 end
439
440 def current_version
441 migrated.last || 0
442 end
443
444 def current_migration
445 migrations.detect { |m| m.version == current_version }
446 end
447
448 def run
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)
454 end
455 end
456
457 def migrate
458 current = migrations.detect { |m| m.version == current_version }
459 target = migrations.detect { |m| m.version == @target_version }
460
461 if target.nil? && !@target_version.nil? && @target_version > 0
462 raise UnknownMigrationVersionError.new(@target_version)
463 end
464
465 start = up? ? 0 : (migrations.index(current) || 0)
466 finish = migrations.index(target) || migrations.size - 1
467 runnable = migrations[start..finish]
468
469 # skip the last migration if we're headed down, but not ALL the way down
470 runnable.pop if down? && !target.nil?
471
472 runnable.each do |migration|
473 Base.logger.info "Migrating to #{migration.name} (#{migration.version})"
474
475 # On our way up, we skip migrating the ones we've already migrated
476 next if up? && migrated.include?(migration.version.to_i)
477
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
481 next
482 end
483
484 begin
485 ddl_transaction do
486 migration.migrate(@direction)
487 record_version_state_after_migrating(migration.version)
488 end
489 rescue => e
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
492 end
493 end
494 end
495
496 def migrations
497 @migrations ||= begin
498 files = Dir["#{@migrations_path}/[0-9]*_*.rb"]
499
500 migrations = files.inject([]) do |klasses, file|
501 version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
502
503 raise IllegalMigrationNameError.new(file) unless version
504 version = version.to_i
505
506 if klasses.detect { |m| m.version == version }
507 raise DuplicateMigrationVersionError.new(version)
508 end
509
510 if klasses.detect { |m| m.name == name.camelize }
511 raise DuplicateMigrationNameError.new(name.camelize)
512 end
513
514 klasses << returning(MigrationProxy.new) do |migration|
515 migration.name = name.camelize
516 migration.version = version
517 migration.filename = file
518 end
519 end
520
521 migrations = migrations.sort_by(&:version)
522 down? ? migrations.reverse : migrations
523 end
524 end
525
526 def pending_migrations
527 already_migrated = migrated
528 migrations.reject { |m| already_migrated.include?(m.version.to_i) }
529 end
530
531 def migrated
532 @migrated_versions ||= self.class.get_all_versions
533 end
534
535 private
536 def record_version_state_after_migrating(version)
537 sm_table = self.class.schema_migrations_table_name
538
539 @migrated_versions ||= []
540 if down?
541 @migrated_versions.delete(version.to_i)
542 Base.connection.update("DELETE FROM #{sm_table} WHERE version = '#{version}'")
543 else
544 @migrated_versions.push(version.to_i).sort!
545 Base.connection.insert("INSERT INTO #{sm_table} (version) VALUES ('#{version}')")
546 end
547 end
548
549 def up?
550 @direction == :up
551 end
552
553 def down?
554 @direction == :down
555 end
556
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 }
561 else
562 block.call
563 end
564 end
565 end
566 end