migrations.textile 29.9 KB
Newer Older
1 2
h2. Migrations

J
Jason Noble 已提交
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Migrations are a convenient way for you to alter your database in a structured
and organized manner. You could edit fragments of SQL by hand but you would then
be responsible for telling other developers that they need to go and run them.
You'd also have to keep track of which changes need to be run against the
production machines next time you deploy.

Active Record tracks which migrations have already been run so all you have to
do is update your source and run +rake db:migrate+. Active Record will work out
which migrations should be run. It will also update your +db/schema.rb+ file to
match the structure of your database.

Migrations also allow you to describe these transformations using Ruby. The
great thing about this is that (like most of Active Record's functionality) it
is database independent: you don't need to worry about the precise syntax of
+CREATE TABLE+ any more than you worry about variations on +SELECT *+ (you can
drop down to raw SQL for database specific features). For example you could use
SQLite3 in development, but MySQL in production.
20

21
In this guide, you'll learn all about migrations including:
22

23 24 25 26
* The generators you can use to create them 
* The methods Active Record provides to manipulate your database 
* The Rake tasks that manipulate them 
* How they relate to +schema.rb+
27 28 29

endprologue.

P
Pratik Naik 已提交
30
h3. Anatomy of a Migration
31

J
Jason Noble 已提交
32 33
Before we dive into the details of a migration, here are a few examples of the
sorts of things you can do:
34 35 36

<ruby>
class CreateProducts < ActiveRecord::Migration
37
  def up
J
Jason Noble 已提交
38
    create_table :products do |t| 
39 40 41 42 43 44 45
      t.string :name
      t.text :description

      t.timestamps
    end
  end

46
  def down
47 48 49 50 51
    drop_table :products
  end
end
</ruby>

J
Jason Noble 已提交
52 53 54 55 56 57
This migration adds a table called +products+ with a string column called +name+
and a text column called +description+. A primary key column called +id+ will
also be added, however since this is the default we do not need to ask for this.
The timestamp columns +created_at+ and +updated_at+ which Active Record
populates automatically will also be added. Reversing this migration is as
simple as dropping the table.
58

J
Jason Noble 已提交
59 60
Migrations are not limited to changing the schema. You can also use them to fix
bad data in the database or populate new fields:
61 62 63

<ruby>
class AddReceiveNewsletterToUsers < ActiveRecord::Migration
64
  def up
J
Jason Noble 已提交
65
    change_table :users do |t| 
66 67 68 69 70
      t.boolean :receive_newsletter, :default => false
    end
    User.update_all ["receive_newsletter = ?", true]
  end

71
  def down
72 73 74 75 76
    remove_column :users, :receive_newsletter
  end
end
</ruby>

J
Jason Noble 已提交
77 78
NOTE: Some "caveats":#using-models-in-your-migrations apply to using models in
your migrations.
V
Vijay Dev 已提交
79

J
Jason Noble 已提交
80 81 82 83
This migration adds a +receive_newsletter+ column to the +users+ table. We want
it to default to +false+ for new users, but existing users are considered to
have already opted in, so we use the User model to set the flag to +true+ for
existing users.
84

J
Jason Noble 已提交
85 86 87 88
Rails 3.1 makes migrations smarter by providing a new <tt>change</tt> method.
This method is preferred for writing constructive migrations (adding columns or
tables). The migration knows how to migrate your database and reverse it when
the migration is rolled back without the need to write a separate +down+ method.
89 90 91 92

<ruby>
class CreateProducts < ActiveRecord::Migration
  def change
J
Jason Noble 已提交
93
    create_table :products do |t| 
94 95 96 97 98 99 100 101 102
      t.string :name
      t.text :description

      t.timestamps
    end
  end
end
</ruby>

P
Pratik Naik 已提交
103
h4. Migrations are Classes
104

J
Jason Noble 已提交
105 106 107
A migration is a subclass of <tt>ActiveRecord::Migration</tt> that implements
two methods: +up+ (perform the required transformations) and +down+ (revert
them).
108

J
Jason Noble 已提交
109 110
Active Record provides methods that perform common data definition tasks in a
database independent way (you'll read about them in detail later):
111

112 113 114 115 116 117 118 119 120
* +add_column+
* +add_index+
* +change_column+
* +change_table+
* +create_table+ 
* +drop_table+
* +remove_column+
* +remove_index+
* +rename_column+
121

J
Jason Noble 已提交
122 123 124 125 126 127
If you need to perform tasks specific to your database (for example create a
"foreign key":#active-record-and-referential-integrity constraint) then the
+execute+ method allows you to execute arbitrary SQL. A migration is just a
regular Ruby class so you're not limited to these functions. For example after
adding a column you could write code to set the value of that column for
existing records (if necessary using your models).
128

J
Jason Noble 已提交
129 130 131
On databases that support transactions with statements that change the schema
(such as PostgreSQL or SQLite3), migrations are wrapped in a transaction. If the
database does not support this (for example MySQL) then when a migration fails
132
the parts of it that succeeded will not be rolled back. You will have to rollback
J
Jason Noble 已提交
133
the changes that were made by hand.
134

P
Pratik Naik 已提交
135
h4. What's in a Name
136

J
Jason Noble 已提交
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
Migrations are stored as files in the +db/migrate+ directory, one for each 
migration class. The name of the file is of the form 
+YYYYMMDDHHMMSS_create_products.rb+, that is to say a UTC timestamp 
identifying the migration followed by an underscore followed by the name 
of the migration. The name of the migration class (CamelCased version) 
should match the latter part of the file name. For example
+20080906120000_create_products.rb+ should define class +CreateProducts+ and
+20080906120001_add_details_to_products.rb+ should define
+AddDetailsToProducts+. If you do feel the need to change the file name then you
<em>have to</em> update the name of the class inside or Rails will complain
about a missing class.

Internally Rails only uses the migration's number (the timestamp) to identify
them. Prior to Rails 2.1 the migration number started at 1 and was incremented
each time a migration was generated. With multiple developers it was easy for
these to clash requiring you to rollback migrations and renumber them. With
Rails 2.1+ this is largely avoided by using the creation time of the migration 
to identify them. You can revert to the old numbering scheme by adding the
following line to +config/application.rb+.
156 157 158 159

<ruby>
config.active_record.timestamped_migrations = false
</ruby>
160

J
Jason Noble 已提交
161 162
The combination of timestamps and recording which migrations have been run
allows Rails to handle common situations that occur with multiple developers.
163

J
Jason Noble 已提交
164 165
For example Alice adds migrations +20080906120000+ and +20080906123000+ and Bob
adds +20080906124500+ and runs it. Alice finishes her changes and checks in her
J
Jason Noble 已提交
166 167 168
migrations and Bob pulls down the latest changes. When Bob runs +rake 
db:migrate+, Rails knows that it has not run Alice's two migrations so it 
executes the +up+ method for each migration.  
169

J
Jason Noble 已提交
170 171 172
Of course this is no substitution for communication within the team. For
example, if Alice's migration removed a table that Bob's migration assumed to
exist, then trouble would certainly strike.
173

P
Pratik Naik 已提交
174
h4. Changing Migrations
175

J
Jason Noble 已提交
176 177 178 179 180 181 182 183 184 185 186 187 188 189
Occasionally you will make a mistake when writing a migration. If you have
already run the migration then you cannot just edit the migration and run the
migration again: Rails thinks it has already run the migration and so will do
nothing when you run +rake db:migrate+. You must rollback the migration (for
example with +rake db:rollback+), edit your migration and then run +rake
db:migrate+ to run the corrected version.

In general editing existing migrations is not a good idea: you will be creating
extra work for yourself and your co-workers and cause major headaches if the
existing version of the migration has already been run on production machines.
Instead, you should write a new migration that performs the changes you require.
Editing a freshly generated migration that has not yet been committed to source
control (or, more generally, which has not been propagated beyond your
development machine) is relatively harmless.
190

D
Daniel Dyba 已提交
191 192
h4. Supported Types

193 194 195 196 197 198 199 200 201 202 203 204 205 206
Active Record supports the following database column types:

* +:binary+
* +:boolean+
* +:date+
* +:datetime+
* +:decimal+
* +:float+
* +:integer+
* +:primary_key+
* +:string+
* +:text+
* +:time+
* +:timestamp+
J
Jason Noble 已提交
207 208 209 210 211

These will be mapped onto an appropriate underlying database type. For example,
with MySQL the type +:string+ is mapped to +VARCHAR(255)+. You can create
columns of types not supported by Active Record when using the non-sexy syntax,
for example
D
Daniel Dyba 已提交
212 213 214 215 216 217 218 219 220

<ruby>
create_table :products do |t|
  t.column :name, 'polygon', :null => false
end
</ruby>

This may however hinder portability to other databases.

P
Pratik Naik 已提交
221
h3. Creating a Migration
222

P
Pratik Naik 已提交
223
h4. Creating a Model
224

J
Jason Noble 已提交
225 226 227 228
The model and scaffold generators will create migrations appropriate for adding
a new model. This migration will already contain instructions for creating the
relevant table. If you tell Rails what columns you want, then statements for
adding these columns will also be created. For example, running
229

P
Pratik Naik 已提交
230
<shell>
231
$ rails generate model Product name:string description:text
P
Pratik Naik 已提交
232 233 234
</shell>

will create a migration that looks like this
235 236 237

<ruby>
class CreateProducts < ActiveRecord::Migration
238
  def change
239 240 241 242 243 244 245 246 247 248
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end
end
</ruby>

249 250 251 252
You can append as many column name/type pairs as you want. By default, the 
generated migration will include +t.timestamps+ (which creates the 
+updated_at+ and +created_at+ columns that are automatically populated 
by Active Record).
253

P
Pratik Naik 已提交
254
h4. Creating a Standalone Migration
255

J
Jason Noble 已提交
256
If you are creating migrations for other purposes (for example to add a column
J
Jason Noble 已提交
257
to an existing table) then you can also use the migration generator:
258

J
Jason Noble 已提交
259
<shell> 
260
$ rails generate migration AddPartNumberToProducts
261 262 263 264 265 266
</shell>

This will create an empty but appropriately named migration:

<ruby>
class AddPartNumberToProducts < ActiveRecord::Migration
267
  def change
268 269 270 271
  end
end
</ruby>

J
Jason Noble 已提交
272 273 274
If the migration name is of the form "AddXXXToYYY" or "RemoveXXXFromYYY" and is
followed by a list of column names and types then a migration containing the
appropriate +add_column+ and +remove_column+ statements will be created.
275 276

<shell>
277
$ rails generate migration AddPartNumberToProducts part_number:string
278 279 280 281 282 283
</shell>

will generate

<ruby>
class AddPartNumberToProducts < ActiveRecord::Migration
284
  def change
285 286 287 288 289 290 291 292
    add_column :products, :part_number, :string
  end
end
</ruby>

Similarly,

<shell>
293
$ rails generate migration RemovePartNumberFromProducts part_number:string
294 295 296 297 298 299
</shell>

generates

<ruby>
class RemovePartNumberFromProducts < ActiveRecord::Migration
300
  def up
301 302 303
    remove_column :products, :part_number
  end

304
  def down
305 306 307 308 309 310 311
    add_column :products, :part_number, :string
  end
end

You are not limited to one magically generated column, for example

<shell>
312
$ rails generate migration AddDetailsToProducts part_number:string price:decimal
313 314 315 316 317 318
</shell>

generates

<ruby>
class AddDetailsToProducts < ActiveRecord::Migration
319
  def change
320 321 322 323 324 325
    add_column :products, :part_number, :string
    add_column :products, :price, :decimal
  end
end
</ruby>

J
Jason Noble 已提交
326 327
As always, what has been generated for you is just a starting point. You can add
or remove from it as you see fit.
328

J
Jason Noble 已提交
329
NOTE: The generated migration file for destructive migrations will still be
330
old-style using the +up+ and +down+ methods. This is because Rails needs to know
J
Jason Noble 已提交
331
the original data types defined when you made the original changes.
V
Vijay Dev 已提交
332

333 334
h3. Writing a Migration

J
Jason Noble 已提交
335 336
Once you have created your migration using one of the generators it's time to
get to work!
337

P
Pratik Naik 已提交
338
h4. Creating a Table
339

J
Jason Noble 已提交
340 341
Migration method +create_table+ will be one of your workhorses. A typical use
would be
342 343 344 345 346 347 348

<ruby>
create_table :products do |t|
  t.string :name
end
</ruby>

J
Jason Noble 已提交
349 350
which creates a +products+ table with a column called +name+ (and as discussed
below, an implicit +id+ column).
351

J
Jason Noble 已提交
352 353
The object yielded to the block allows you to create columns on the table. There
are two ways of doing it. The first (traditional) form looks like
354 355 356 357 358 359 360

<ruby>
create_table :products do |t|
  t.column :name, :string, :null => false
end
</ruby>

J
Jason Noble 已提交
361 362 363
The second form, the so called "sexy" migration, drops the somewhat redundant
+column+ method. Instead, the +string+, +integer+, etc. methods create a column
of that type. Subsequent parameters are the same.
364 365 366 367 368 369 370

<ruby>
create_table :products do |t|
  t.string :name, :null => false
end
</ruby>

J
Jason Noble 已提交
371 372 373 374
By default, +create_table+ will create a primary key called +id+. You can change
the name of the primary key with the +:primary_key+ option (don't forget to
update the corresponding model) or, if you don't want a primary key at all (for
example for a HABTM join table), you can pass the option +:id => false+. If you
J
Jason Noble 已提交
375
need to pass database specific options you can place a SQL fragment in the
J
Jason Noble 已提交
376
+:options+ option. For example,
377 378 379 380 381 382 383

<ruby>
create_table :products, :options => "ENGINE=BLACKHOLE" do |t|
  t.string :name, :null => false
end
</ruby>

J
Jason Noble 已提交
384 385
will append +ENGINE=BLACKHOLE+ to the SQL statement used to create the table
(when using MySQL, the default is +ENGINE=InnoDB+).
P
Pratik Naik 已提交
386

P
Pratik Naik 已提交
387
h4. Changing Tables
388

J
Jason Noble 已提交
389 390 391
A close cousin of +create_table+ is +change_table+, used for changing existing
tables. It is used in a similar fashion to +create_table+ but the object yielded
to the block knows more tricks. For example
392 393 394 395 396 397 398 399 400

<ruby>
change_table :products do |t|
  t.remove :description, :name
  t.string :part_number
  t.index :part_number
  t.rename :upccode, :upc_code
end
</ruby>
401

J
Jason Noble 已提交
402 403
removes the +description+ and +name+ columns, creates a +part_number+ string 
column and adds an index on it. Finally it renames the +upccode+ column. 
404

P
Pratik Naik 已提交
405
h4. Special Helpers
406

J
Jason Noble 已提交
407 408 409
Active Record provides some shortcuts for common functionality. It is for
example very common to add both the +created_at+ and +updated_at+ columns and so
there is a method that does exactly that:
410 411 412 413 414 415 416

<ruby>
create_table :products do |t|
  t.timestamps
end
</ruby>

J
Jason Noble 已提交
417 418 419
will create a new products table with those two columns (plus the +id+ column)
whereas

420 421 422 423 424 425 426
<ruby>
change_table :products do |t|
  t.timestamps
end
</ruby>
adds those columns to an existing table.

J
Jason Noble 已提交
427
Another helper is called +references+ (also available as +belongs_to+). In its
J
Jason Noble 已提交
428
simplest form it just adds some readability
429 430 431 432 433 434 435

<ruby>
create_table :products do |t|
  t.references :category
end
</ruby>

J
Jason Noble 已提交
436 437 438 439
will create a +category_id+ column of the appropriate type. Note that you pass
the model name, not the column name. Active Record adds the +_id+ for you. If
you have polymorphic +belongs_to+ associations then +references+ will add both
of the columns required:
440 441 442 443 444 445 446

<ruby>
create_table :products do |t|
  t.references :attachment, :polymorphic => {:default => 'Photo'}
end
</ruby>

J
Jason Noble 已提交
447 448
will add an +attachment_id+ column and a string +attachment_type+ column with 
a default value of 'Photo'.
449

J
Jason Noble 已提交
450 451 452
NOTE: The +references+ helper does not actually create foreign key constraints
for you. You will need to use +execute+ or a plugin that adds "foreign key
support":#active-record-and-referential-integrity.
453

J
Jason Noble 已提交
454 455 456 457 458 459 460 461 462 463 464 465
If the helpers provided by Active Record aren't enough you can use the +execute+
method to execute arbitrary SQL.

For more details and examples of individual methods, check the API documentation,
in particular the documentation for
"<tt>ActiveRecord::ConnectionAdapters::SchemaStatements</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html
(which provides the methods available in the +up+ and +down+ methods),
"<tt>ActiveRecord::ConnectionAdapters::TableDefinition</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/TableDefinition.html
(which provides the methods available on the object yielded by +create_table+)
and
"<tt>ActiveRecord::ConnectionAdapters::Table</tt>":http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html
(which provides the methods available on the object yielded by +change_table+).
466

467
h4. Using the +change+ Method
468

J
Jason Noble 已提交
469 470 471
The +change+ method removes the need to write both +up+ and +down+ methods in
those cases that Rails know how to revert the changes automatically. Currently,
the +change+ method supports only these migration definitions:
472

473 474 475 476 477 478 479 480
* +add_column+
* +add_index+
* +add_timestamps+
* +create_table+
* +remove_timestamps+
* +rename_column+
* +rename_index+
* +rename_table+
481

482 483
If you're going to need to use any other methods, you'll have to write the 
+up+ and +down+ methods instead of using the change method.
484

485
h4. Using the +up+/+down+ Methods
486

J
Jason Noble 已提交
487 488 489 490 491 492
The +down+ method of your migration should revert the transformations done by
the +up+ method. In other words, the database schema should be unchanged if you
do an +up+ followed by a +down+. For example, if you create a table in the +up+
method, you should drop it in the +down+ method. It is wise to reverse the
transformations in precisely the reverse order they were made in the +up+
method. For example,
493 494 495

<ruby>
class ExampleMigration < ActiveRecord::Migration
496
  def up
497 498 499 500
    create_table :products do |t|
      t.references :category
    end
    #add a foreign key
P
Pratik Naik 已提交
501 502 503 504 505 506
    execute <<-SQL
      ALTER TABLE products
        ADD CONSTRAINT fk_products_categories
        FOREIGN KEY (category_id)
        REFERENCES categories(id)
    SQL
507 508 509 510
    add_column :users, :home_page_url, :string
    rename_column :users, :email, :email_address
  end

511
  def down
512 513
    rename_column :users, :email_address, :email
    remove_column :users, :home_page_url
J
Jason Noble 已提交
514 515 516 517
    execute <<-SQL
      ALTER TABLE products
        DROP FOREIGN KEY fk_products_categories
    SQL
518 519 520 521 522
    drop_table :products
  end
end
</ruby>

J
Jason Noble 已提交
523 524 525 526 527
Sometimes your migration will do something which is just plain irreversible; for
example, it might destroy some data. In such cases, you can raise
+ActiveRecord::IrreversibleMigration+ from your +down+ method. If someone tries
to revert your migration, an error message will be displayed saying that it
can't be done.
528 529 530

h3. Running Migrations

J
Jason Noble 已提交
531
Rails provides a set of rake tasks to work with migrations which boil down to
532 533 534 535 536 537 538
running certain sets of migrations. 

The very first migration related rake task you will use will probably be 
+rake db:migrate+. In its most basic form it just runs the +up+ or +change+
method for all the migrations that have not yet been run. If there are
no such migrations, it exits. It will run these migrations in order based
on the date of the migration.
539

J
Jason Noble 已提交
540 541
Note that running the +db:migrate+ also invokes the +db:schema:dump+ task, which
will update your db/schema.rb file to match the structure of your database.
542

J
Jason Noble 已提交
543
If you specify a target version, Active Record will run the required migrations
544 545 546
(up or down or change) until it has reached the specified version. The version 
is the numerical prefix on the migration's filename. For example, to migrate 
to version 20080906120000 run
547 548

<shell>
549
$ rake db:migrate VERSION=20080906120000
550 551
</shell>

J
Jason Noble 已提交
552 553
If version 20080906120000 is greater than the current version (i.e., it is
migrating upwards), this will run the +up+ method on all migrations up to and
554 555 556
including 20080906120000, and will not execute any later migrations. If 
migrating downwards, this will run the +down+ method on all the migrations 
down to, but not including, 20080906120000.
557

P
Pratik Naik 已提交
558
h4. Rolling Back
559

J
Jason Noble 已提交
560 561 562
A common task is to rollback the last migration, for example if you made a
mistake in it and wish to correct it. Rather than tracking down the version
number associated with the previous migration you can run
563 564

<shell>
565
$ rake db:rollback
566 567
</shell>

J
Jason Noble 已提交
568 569
This will run the +down+ method from the latest migration. If you need to undo
several migrations you can provide a +STEP+ parameter:
570 571

<shell>
572
$ rake db:rollback STEP=3
573 574 575 576
</shell>

will run the +down+ method from the last 3 migrations.

J
Jason Noble 已提交
577 578 579
The +db:migrate:redo+ task is a shortcut for doing a rollback and then migrating
back up again. As with the +db:rollback+ task, you can use the +STEP+ parameter
if you need to go more than one version back, for example
580 581

<shell>
582
$ rake db:migrate:redo STEP=3
583 584
</shell>

J
Jason Noble 已提交
585 586 587
Neither of these Rake tasks do anything you could not do with +db:migrate+. They
are simply more convenient, since you do not need to explicitly specify the
version to migrate to.
588

589 590 591
h4. Resetting the database

The +rake db:reset+ task will drop the database, recreate it and load the
J
Jason Noble 已提交
592
current schema into it.
593

J
Jason Noble 已提交
594 595
NOTE: This is not the same as running all the migrations - see the section on
"schema.rb":#schema-dumping-and-you.
596

J
Jason Noble 已提交
597
h4. Running specific migrations
598

J
Jason Noble 已提交
599 600 601 602
If you need to run a specific migration up or down, the +db:migrate:up+ and
+db:migrate:down+ tasks will do that. Just specify the appropriate version and
the corresponding migration will have its +up+ or +down+ method invoked, for
example,
603 604

<shell>
605
$ rake db:migrate:up VERSION=20080906120000
606 607
</shell>

J
Jason Noble 已提交
608 609
will run the +up+ method from the 20080906120000 migration. These tasks still
check whether the migration has already run, so for example +db:migrate:up
J
Jason Noble 已提交
610 611
VERSION=20080906120000+ will do nothing if Active Record believes that
20080906120000 has already been run.
612

613
h4. Changing the output of running migrations
614

J
Jason Noble 已提交
615 616
By default migrations tell you exactly what they're doing and how long it took.
A migration creating a table and adding an index might produce output like this
617 618

<shell>
J
Jason Noble 已提交
619
==  CreateProducts: migrating =================================================
620
-- create_table(:products)
J
Jason Noble 已提交
621 622
   -> 0.0028s
==  CreateProducts: migrated (0.0028s) ========================================
623 624
</shell>

625 626 627 628 629 630 631 632 633 634 635
Several methods are provided in migrations that allow you to control all this:

|_.Method             |_.Purpose|
|suppress_messages    |takes a block as an argument and suppresses any output
                       generated by the block.|
|say                  |Takes a message argument and outputs it as is. A second
                       boolean argument can be passed to specify whether to
                       indent or not.|
|say_with_time        |Outputs text along with how long it took to run its
                       block. If the block returns an integer it assumes it 
                       is the number of rows affected.|
636 637 638

For example, this migration

V
Vijay Dev 已提交
639
<ruby>
640
class CreateProducts < ActiveRecord::Migration
641
  def change
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
    suppress_messages do
      create_table :products do |t|
        t.string :name
        t.text :description
        t.timestamps
      end
    end
    say "Created a table"
    suppress_messages {add_index :products, :name}
    say "and an index!", true
    say_with_time 'Waiting for a while' do
      sleep 10
      250
    end
  end
end
V
Vijay Dev 已提交
658
</ruby>
659 660 661 662

generates the following output

<shell>
J
Jason Noble 已提交
663 664
==  CreateProducts: migrating =================================================
-- Created a table
665
   -> and an index!
J
Jason Noble 已提交
666 667
-- Waiting for a while
   -> 10.0013s
668
   -> 250 rows
J
Jason Noble 已提交
669
==  CreateProducts: migrated (10.0054s) =======================================
670 671
</shell>

J
Jason Noble 已提交
672
If you want Active Record to not output anything, then running +rake db:migrate
J
Jason Noble 已提交
673
VERBOSE=false+ will suppress all output.
674

P
Pratik Naik 已提交
675
h3. Using Models in Your Migrations
676

J
Jason Noble 已提交
677 678 679
When creating or updating data in a migration it is often tempting to use one of
your models. After all, they exist to provide easy access to the underlying
data. This can be done, but some caution should be observed.
680

J
Jason Noble 已提交
681 682 683
For example, problems occur when the model uses database columns which are (1)
not currently in the database and (2) will be created by this or a subsequent
migration.
684

J
Jason Noble 已提交
685 686
Consider this example, where Alice and Bob are working on the same code base
which contains a +Product+ model:
687

688 689
Bob goes on vacation.

J
Jason Noble 已提交
690 691 692
Alice creates a migration for the +products+ table which adds a new column and
initializes it.  She also adds a validation to the +Product+ model for the new
column.
693

V
Vijay Dev 已提交
694
<ruby>
695 696 697 698
# db/migrate/20100513121110_add_flag_to_product.rb

class AddFlagToProduct < ActiveRecord::Migration
  def change
J
Jason Noble 已提交
699 700 701 702
    add_column :products, :flag, :boolean
    Product.all.each do |product|
      product.update_attributes!(:flag => 'false')
    end
703
  end
704
end
V
Vijay Dev 已提交
705
</ruby>
706

V
Vijay Dev 已提交
707
<ruby>
708 709 710
# app/model/product.rb

class Product < ActiveRecord::Base
V
Vijay Dev 已提交
711
  validates :flag, :presence => true
712
end
V
Vijay Dev 已提交
713
</ruby>
714

J
Jason Noble 已提交
715 716 717
Alice adds a second migration which adds and initializes another column to the
+products+ table and also adds a validation to the +Product+ model for the new
column.
718

V
Vijay Dev 已提交
719
<ruby>
720 721 722
# db/migrate/20100515121110_add_fuzz_to_product.rb

class AddFuzzToProduct < ActiveRecord::Migration
723
  def change
724
    add_column :products, :fuzz, :string
J
Jason Noble 已提交
725 726 727
    Product.all.each do |product|
      product.update_attributes! :fuzz => 'fuzzy'
    end
728 729
  end
end
V
Vijay Dev 已提交
730
</ruby>
731

V
Vijay Dev 已提交
732
<ruby>
733
# app/model/product.rb
734

735
class Product < ActiveRecord::Base
V
Vijay Dev 已提交
736
  validates :flag, :fuzz, :presence => true
737
end
V
Vijay Dev 已提交
738
</ruby>
739

740 741 742 743
Both migrations work for Alice.

Bob comes back from vacation and:

J
Jason Noble 已提交
744 745 746 747
# Updates the source - which contains both migrations and the latests version of
the Product model.
# Runs outstanding migrations with +rake db:migrate+, which
includes the one that updates the +Product+ model.
748

J
Jason Noble 已提交
749 750 751
The migration crashes because when the model attempts to save, it tries to
validate the second added column, which is not in the database when the _first_
migration runs:
752

V
Vijay Dev 已提交
753
<plain>
754 755 756 757
rake aborted!
An error has occurred, this and all later migrations canceled:

undefined method `fuzz' for #<Product:0x000001049b14a0>
V
Vijay Dev 已提交
758
</plain>
759

J
Jason Noble 已提交
760 761
A fix for this is to create a local model within the migration. This keeps rails
from running the validations, so that the migrations run to completion.
762

J
Jason Noble 已提交
763 764 765
When using a faux model, it's a good idea to call
+Product.reset_column_information+ to refresh the +ActiveRecord+ cache for the
+Product+ model prior to updating data in the database.
766 767 768

If Alice had done this instead, there would have been no problem:

V
Vijay Dev 已提交
769
<ruby>
770 771
# db/migrate/20100513121110_add_flag_to_product.rb

J
Jason Noble 已提交
772
class AddFlagToProduct < ActiveRecord::Migration 
773 774
  class Product < ActiveRecord::Base
  end
V
Vijay Dev 已提交
775

776
  def change
J
Jason Noble 已提交
777
    add_column :products, :flag, :integer
V
Vijay Dev 已提交
778
    Product.reset_column_information
J
Jason Noble 已提交
779 780 781
    Product.all.each do |product|
      product.update_attributes!(:flag => false)
    end
782 783
  end
end
V
Vijay Dev 已提交
784
</ruby>
785

V
Vijay Dev 已提交
786
<ruby>
787 788 789 790 791
# db/migrate/20100515121110_add_fuzz_to_product.rb

class AddFuzzToProduct < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end
J
Jason Noble 已提交
792
  
793
  def change
794
    add_column :products, :fuzz, :string
795
    Product.reset_column_information
J
Jason Noble 已提交
796 797 798
    Product.all.each do |product|
      product.update_attributes!(:fuzz => 'fuzzy')
    end
799 800
  end
end
V
Vijay Dev 已提交
801
</ruby>
802

P
Pratik Naik 已提交
803
h3. Schema Dumping and You
804

P
Pratik Naik 已提交
805
h4. What are Schema Files for?
806

J
Jason Noble 已提交
807
Migrations, mighty as they may be, are not the authoritative source for your
J
Jason Noble 已提交
808
database schema. That role falls to either +db/schema.rb+ or a SQL file which
J
Jason Noble 已提交
809 810
Active Record generates by examining the database. They are not designed to be
edited, they just represent the current state of the database.
811

J
Jason Noble 已提交
812 813 814
There is no need (and it is error prone) to deploy a new instance of an app by
replaying the entire migration history. It is much simpler and faster to just
load into the database a description of the current schema.
815

J
Jason Noble 已提交
816 817 818
For example, this is how the test database is created: the current development
database is dumped (either to +db/schema.rb+ or +db/development.sql+) and then
loaded into the test database.
819

J
Jason Noble 已提交
820 821
Schema files are also useful if you want a quick look at what attributes an
Active Record object has. This information is not in the model's code and is
J
Jason Noble 已提交
822 823 824 825 826
frequently spread across several migrations, but the information is nicely 
summed up in the schema file. The 
"annotate_models":https://github.com/ctran/annotate_models gem automatically 
adds and updates comments at the top of each model summarizing the schema if 
you desire that functionality.
827

P
Pratik Naik 已提交
828
h4. Types of Schema Dumps
829

J
Jason Noble 已提交
830 831 832
There are two ways to dump the schema. This is set in +config/application.rb+ by
the +config.active_record.schema_format+ setting, which may be either +:sql+ or
+:ruby+.
833

J
Jason Noble 已提交
834 835
If +:ruby+ is selected then the schema is stored in +db/schema.rb+. If you look
at this file you'll find that it looks an awful lot like one very big migration:
836 837 838 839 840 841 842 843 844 845 846

<ruby>
ActiveRecord::Schema.define(:version => 20080906171750) do
  create_table "authors", :force => true do |t|
    t.string   "name"
    t.datetime "created_at"
    t.datetime "updated_at"
  end

  create_table "products", :force => true do |t|
    t.string   "name"
J
Jason Noble 已提交
847
    t.text "description"
848 849
    t.datetime "created_at"
    t.datetime "updated_at"
J
Jason Noble 已提交
850
    t.string "part_number"
851 852 853 854
  end
end
</ruby>

J
Jason Noble 已提交
855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
In many ways this is exactly what it is. This file is created by inspecting the
database and expressing its structure using +create_table+, +add_index+, and so
on. Because this is database-independent, it could be loaded into any database
that Active Record supports. This could be very useful if you were to distribute
an application that is able to run against multiple databases.

There is however a trade-off: +db/schema.rb+ cannot express database specific
items such as foreign key constraints, triggers, or stored procedures. While in
a migration you can execute custom SQL statements, the schema dumper cannot
reconstitute those statements from the database. If you are using features like
this, then you should set the schema format to +:sql+.

Instead of using Active Record's schema dumper, the database's structure will be
dumped using a tool specific to the database (via the +db:structure:dump+ Rake
task) into +db/structure.sql+. For example, for the PostgreSQL RDBMS, the
+pg_dump+ utility is used. For MySQL, this file will contain the output of +SHOW
CREATE TABLE+ for the various tables. Loading these schemas is simply a question
of executing the SQL statements they contain. By definition, this will create a
perfect copy of the database's structure. Using the +:sql+ schema format will,
however, prevent loading the schema into a RDBMS other than the one used to
create it.
876

P
Pratik Naik 已提交
877
h4. Schema Dumps and Source Control
878

J
Jason Noble 已提交
879 880
Because schema dumps are the authoritative source for your database schema, it
is strongly recommended that you check them into source control.
881 882 883

h3. Active Record and Referential Integrity

J
Jason Noble 已提交
884 885 886 887 888 889 890 891 892 893
The Active Record way claims that intelligence belongs in your models, not in
the database. As such, features such as triggers or foreign key constraints,
which push some of that intelligence back into the database, are not heavily
used.

Validations such as +validates :foreign_key, :uniqueness => true+ are one way in
which models can enforce data integrity. The +:dependent+ option on associations
allows models to automatically destroy child objects when the parent is
destroyed. Like anything which operates at the application level, these cannot
guarantee referential integrity and so some people augment them with foreign key
894
constraints in the database.
J
Jason Noble 已提交
895 896 897 898 899 900

Although Active Record does not provide any tools for working directly with such
features, the +execute+ method can be used to execute arbitrary SQL. You could
also use some plugin like "foreigner":https://github.com/matthuhiggins/foreigner
which add foreign key support to Active Record (including support for dumping
foreign keys in +db/schema.rb+).