Last-modified: 2010-09-19 (日) 18:42:35 (4h)

RailsGuidesをゆっくり和訳してみたよ

Rails Database Migrations

原文

http://guides.rubyonrails.org/migrations.html

マイグレーション(Migrations)

マイグレーションは、構造的で組織的な方法でデータベースを変更するための、便利な方法です。
手作業でSQLの断片を編集できますが、他の開発者たちが実行する必要がある時、それを伝える責任があります。
productionマシンに対して次回デプロイする時に、どの変更が必要か追跡する必要があります。

Active Record は、どのマイグレーションが既に実行されたかを追跡しているので、やらなければならないのはソースを更新し rake db:migrate を実行することだけです。
Active Record はマイグレーションをうまく実行するでしょう。
またデータベースの構造に一致するように db/schema.rb を更新するでしょう。

マイグレーションはこれらの変換をRubyを使って記述することができます。
これについて素晴らしいところ(アクティブレコードの機能の大半のように)は、データベースから独立しています:
SELECT *の種類についてあなたが心配する以上に、CREATE TABLEの正確な構文については何も心配する必要がありません。
(DBの特定の機能の為に生のSQL文を書き下ろすこともできます。)
例えば、developmentでSQLite3を使い、productionでMySQLを使うこともできます。

以下を含む移行のすべてについて学びます:

  • マイグレーションを作成するために使えるジェネレーター
  • DBを操作するためにActive Recordが提供しているメソッド
  • マイグレーションを操作する為のRakeタスク
  • マイグレーションと schema.rb の関連付け方

1 マイグレーションの解剖学(Anatomy of a Migration)

マイグレーションの詳細に飛び込む前に、あなたはどんなことができるかの例がいくつかあります:

class CreateProducts < ActiveRecord::Migration
  def self.up
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end

  def self.down
    drop_table :products
  end
end 

このマイグレーションは、 products というテーブルに name という string カラムと description というテキストカラムを追加します。
idという主キー列も追加されますが、これはデフォルトですので、何もする必要はありません。
timestamps カラムにより、 created_at と updated_at が、Active Recordにより自動的に作成され、追加されるでしょう。
このマイグレーションを反対は、単にテーブルをドロップするだけです。

マイグレーションは、スキーマを変更することだけに留まりません。
データベース内の不正なデータを修正するか、新しいフィールドを作成するのにも使用することができます:

class AddReceiveNewsletterToUsers < ActiveRecord::Migration
  def self.up
    change_table :users do |t|
      t.boolean :receive_newsletter, :default => false
    end
    User.update_all ["receive_newsletter = ?", true]
  end

  def self.down
    remove_column :users, :receive_newsletter
  end
end

このマイグレーションは、 users テーブルに receive_newsletter カラムを追加します。
新しいユーザーのデフォルトを false にしたいが、既存のユーザーはメール受信を許可していると考えられるので
既存のユーザーのためのフラグを true に設定する User モデルを使用します。

マイグレーション内でモデルを使用する際に適用される注意点がいくつかあります。

1.1 マイグレーションはクラスです。(Migrations are Classes)

マイグレーションは ActiveRecord::Migration のサブクラスであり、2つのクラスのメソッドup(必要な変換を実行する)とdown(それらを元に戻す)を実装しています。

データベースに依存しない方法で、一般的なデータ定義のタスクを実行するメソッドを、Active Record は提供します。(詳細は後で読むことになるでしょう)

  • create_table
  • change_table
  • drop_table
  • add_column
  • change_column
  • rename_column
  • remove_column
  • add_index
  • remove_index

特定のタスクをデータベースに実行する必要があるなら(たとえば、外部キー制約を作成する)
execute 関数は、任意のSQLを実行することができます。
マイグレーションは通常のRubyのクラスを使用するので、これらの関数に限界はありません。
例えば、カラムを追加した後に、存在するレコードのカラムの値を設定するコードを書くことができます。(必要に応じてモデルを使用します)

(PostgreSQLやSQLite3のように)スキーマを変更するステートメントのトランザクションをサポートしているデータベースでは
マイグレーションは、トランザクション内にラップされます。
データベースがこれをサポートしていない場合(たとえば、MySQL)
成功したはずのマイグレーションの一部が失敗していても、ロールバックされないでしょう。
手作業で行われた変更を元に戻す必要があるでしょう。

1.2 名前の意味は何?(What’s in a Name)

マイグレーションは db/migrate ファイルに、マイグレーションクラス毎に一つずつ格納されます。
ファイル名はYYYYMMDDHHMMSS_create_products.rbの形式です。
それはUTCタイムスタンプの識別子の後に、アンダースコアでマイグレーションの名前が続いています。
マイグレーションクラスの名前(キャメルケースのバージョン)が、ファイル名の後半に一致する必要があります。
例えば、 20080906120000_create_products.rb は、 CreateProducts を定義しているべきで、
20080906120001_add_details_to_products.rb は、 AddDetailsToProducts を定義しているべきです。
ファイル名を変える必要を感じたなら、クラスの名前を更新しなければいけません、さもなければ、Railsはクラスが見つからないことについて文句を言うでしょう。

内部的にRailsはマイグレーションの番号(タイムスタンプ)を識別するために使用するだけです。
Rails2.1以前のマイグレーションの番号は 1 から始まり、マイグレーションが生成されるたびにインクリメントされていました。
開発者が複数の場合では、簡単に衝突し、マイグレーションをロールバックし、番号をつけ直す必要がありました。
Rails2.1では、識別子にマイグレーションの作成時刻を使用して、これを大きく回避しました。
config/application.rb 内に、以下の行を追加することにより、古い番号方式に戻すことができます。

config.active_record.timestamped_migrations = false

タイムスタンプおよびマイグレーションの実行記録の組み合わせは、複数の開発者で発生する一般的な状況をRailsが処理できるようにします。

例えば、アリスが20080906120000と20080906123000のマイグレーションを追加し、ボブが20080906124500を追加して、実行するとしましょう。
アリスは、変更を済ませ、マイグレーションをcheck inし、ボブが最新の変更をpullしてきました。
Railsはアリスの二つのマイグレーションが実行されていないことを知っているので、rake db:migrate はそれらを実行するでしょう、
(それ以降のタイムスタンプであるボブのマイグレーションが実行されたのにもかかわらず)
同様にマイグレーションのdownはそれらのdownメソッドを実行しないでしょう。

もちろんこれは、チーム内のコミュニケーションの置き換えではありません。
ボブのマイグレーションが存在すると仮定しているテーブルを、アリスのマイグレーションが削除したなら、問題は必ず起こるでしょう。

1.3 マイグレーションを変更する(Changing Migrations)

場合によっては間違ったマイグレーションを書くかもしれません。
既にマイグレーションを実行している場合、それを編集して、再度実行することはできません:
Railsは、すでにマイグレーションを実行したと思っているので、 rake db:migrate を実行しても何もしません。
マイグレーションのロールバックを行わなければいけません。(例えば rake db:rollback を使って。)
マイグレーションを編集し、そして修正されたバージョンを実行するために rake db:migrate を実行してください。

一般的に、既存のマイグレーションを編集することは良い考えではありません:
マイグレーションの既存のバージョンが既に production マシン上で実行されている場合、
あなた自身と一緒に働いている人に余計な作業を増やすことになり、頭痛を引き起こすでしょう。
代わりに、必要な変更を実行する新しいマイグレーションを書くべきです。
まだソース管理システムにコミットされていない、新しく生成されたマイグレーションを編集すること(より一般的には、どの development マシンにも伝播していない)は比較的無害です。
常識で判断しましょう。

2 マイグレーションの作成(Creating a Migration)

2.1 モデルの作成(Creating a Model)

モデルと scaffold ジェネレータは、新しいモデルを追加するための適切なマイグレーションを作成します。
このマイグレーションは、関連するテーブルを作成するための手順が、すでに含まれているでしょう。
Railsに何のカラムが欲しいか伝えれば、それらを追加するためのステートメントもまた作成されるでしょう。
例えば以下を実行してみましょう。

rails generate model Product name:string description:text

このようなマイグレーションを作成します。

class CreateProducts < ActiveRecord::Migration
  def self.up
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end

  def self.down
    drop_table :products
  end
end

必要に応じるだけ、カラムの名前/型のペアを追加できます。
デフォルトで t.timestamps (これはActiveRecordによって自動的に追加される updated_at と created_at カラムを作ります)が、追加されるでしょう。

2.2 スタンドアロンのマイグレーションの作成(Creating a Standalone Migration)

他の目的のために、マイグレーションを作成する場合(例えば既存のテーブルにカラムを追加する)、 migration ジェネレーターを使えます:

rails generate migration AddPartNumberToProducts

これは空っぽのものを作成しますが、適切にマイグレーションを命名します:

class AddPartNumberToProducts < ActiveRecord::Migration
  def self.up
  end

  def self.down
  end
end

マイグレーションの名前を"AddXXXToYYY"か"RemoveXXXFromYYY"の形式にして、カラムの名前と型のリストを続ければ、
適切な add_column と remove_column ステートメントを含むマイグレーションが作成されるでしょう。

rails generate migration AddPartNumberToProducts part_number:string

は以下を作成するでしょう。

class AddPartNumberToProducts < ActiveRecord::Migration
  def self.up
    add_column :products, :part_number, :string
  end

  def self.down
    remove_column :products, :part_number
  end
end

同様に、

rails generate migration RemovePartNumberFromProducts part_number:string

は、以下を作成します。

class RemovePartNumberFromProducts < ActiveRecord::Migration
  def self.up
    remove_column :products, :part_number
  end

  def self.down
    add_column :products, :part_number, :string
  end
end

魔法のように作られたカラムは、一つに限定されません。例えば、

rails generate migration AddDetailsToProducts part_number:string price:decimal

は、以下を作成します。

class AddDetailsToProducts < ActiveRecord::Migration
  def self.up
    add_column :products, :part_number, :string
    add_column :products, :price, :decimal
  end

  def self.down
    remove_column :products, :price
    remove_column :products, :part_number
  end
end

いつものことですが、生成されているものは只の出発点です。
フィットするように、追加したり削除したりできます。

3 マイグレーションの書き方(Writing a Migration)

どれかジェネレーターを使って、一度マイグレーションを作ったなら、動かしてみましょう!

3.1 テーブルの作成(Creating a Table)

マイグレーションのメソッドである cretae_table は、主力の一つになるでしょう。
典型的な使用方法は

create_table :products do |t|
  t.string :name
end

products テーブルを name カラム(及び、以下で説明する暗黙の id カラム)とともに作ります。

ブロックに引き渡されたオブジェクト(訳注:tのこと)により、テーブルにカラムを作成できます。
これを行う2つの方法があります。
最初の(伝統的な)方式は以下のようになります。

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

二番目の方式は、"sexy"マイグレーションと呼ばれていて、やや冗長な column メソッドを捨て去ります。
代わりに、 string 、 integer 、その他のメソッドが、その型のカラムを作ります。
後続のパラメータは同じです。

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

デフォルトでは cretae_table は id という主キーを作成します。 :primary_key オプションを使って、主キーの名前を変更できます(対応するモデルを更新するのを忘れないでください)
また主キーを必要としない場合(例えば、HABTM結合テーブルのため)は、 :id => false を渡すことができます。
データベース固有のオプションを渡す必要がある場合、:option オプション内にSQL文を書くことができます。
例えば、

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

は、テーブルを作成する際のSQL文に ENGINE=BLACKHOLE を追加するでしょう。(MySQLを使うとき、デフォルトは ENGINE=InnoDB )

Active Recordでサポートされている型は、
:primary_key 、 :string 、 :text 、 :integer 、 :float 、 :decimal 、 :datetime 、 :timestamp 、 :time 、 :date 、 :binary 、 :boolean です。

これらは、適切なデータベースの基本型にマッピングされるでしょう。
例えばMySQLでは、 :string は VARCHAR(255) にマップされます。
Active Recordがサポートしていない型のカラムも、sexyじゃない文法を使えば作成できます。
例えば、

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

しかしながら、これは他のデータベースへの移植性を妨げることがあります。

3.2 テーブルの変更(Changing Tables)

cretae_table と似ていてるものに change_table があり、既存のテーブルを変更するために使用されます。
これは cretae_table と同様の方法で使用されますが、ブロックに引き渡されたオブジェクト(訳注:tのこと)はもっとトリッキーに使えます。
例えば、

change_table :products do |t|
  t.remove :description, :name
  t.string :part_number
  t.index :part_number
  t.rename :upccode, :upc_code
end 

は、description と name カラムを削除し、 part_number カラムを作り、それに index を加えます。
そして最後に upccode カラムをリネームします。
これは以下と同じことです。

remove_column :products, :description
remove_column :products, :name
add_column :products, :part_number, :string
add_index :products, :part_number
rename_column :products, :upccode, :upc_code

テーブル名を繰り返し続ける必要がなく、1つの特定のテーブルを変更するのに関連する全てのステートメントをグループ化します。
個々の変換名も短く、例えば remove_column は remove だけになり、 add_index は index だけになります。

3.3 特別なヘルパ(Special Helpers)

Active Record は一般的な機能のために、いくつかのショートカットを提供します。
凄く一般的な例を出すと、 created_at と updated_at カラムの両方を追加するのに、ちょうどいいメソッドがあります。

create_table :products do |t|
  t.timestamps
end 

これは新しい products テーブルを二つのカラム(と id カラムも)と共に作るでしょう。
一方、

change_table :products do |t|
  t.timestamps
end 

は、それらのカラムを既存のテーブルに追加するでしょう。

他には、 references というヘルパがあります(belongs_to のように使えます)。
それのシンプルな形式は、読みやすさへと繋がります。

create_table :products do |t|
  t.references :category
end 

は、適切な型の category_id カラムを作るでしょう。
モデル名を渡すのであって、カラム名を渡すのではないことに注意して下さい。
Active Record は _id を追加します。
一対多の belongs_to アソシエーションがあるなら、 references は必要な両方のカラムを追加するでしょう:

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

は、 attachment_id カラムを追加し、string型の attachment_type カラムを、デフォルト値 'Photo' で作るでしょう。

references ヘルパは、実際に外部キー制約を作成しません。
そうするためには、 execute するか、foreign key support プラグインが必要です。

Active Record によって提供されるヘルパでは十分でない場合、任意のSQLを実行するための execute 関数を使えます。

個々のメソッドの詳細および例については、APIドキュメントを確認してください、
特にActiveRecord::ConnectionAdapters::SchemaStatements(upやdownメソッド内でどのメソッドが利用可能か書いています)
ActiveRecord::ConnectionAdapters::TableDefinition(create_tableによる引き渡されるオブジェクト内でどのメソッドが利用可能か書いています)
ActiveRecord::ConnectionAdapters::Table(change_tableによる引き渡されるオブジェクト内でどのメソッドが利用可能か書いています)

3.4 down メソッドを書く(Writing Your down Method)

マイグレーションの down メソッドは、 up メソッドによって、変換を元に戻せる必要があります。
言い換えれば、 down に続いて up を行った場合、データベースのスキーマが変更されていない必要があります。
例えば、 up メソッド内でテーブルを作成する場合、 down メソッドでそれをドロップして下さい。
up メソッドで行った順を正確にひっくり返すのが賢明なやり方です。
例えば

class ExampleMigration < ActiveRecord::Migration

  def self.up
    create_table :products do |t|
      t.references :category
    end
    #外部キーの追加
    execute <<-SQL
      ALTER TABLE products
        ADD CONSTRAINT fk_products_categories
        FOREIGN KEY (category_id)
        REFERENCES categories(id)
    SQL

    add_column :users, :home_page_url, :string

    rename_column :users, :email, :email_address

  end

  def self.down
    rename_column :users, :email_address, :email
    remove_column :users, :home_page_url
    execute "ALTER TABLE products DROP FOREIGN KEY fk_products_categories"
    drop_table :products
  end
end

時には、あなたのマイグレーションが不可逆な何かをするでしょう。
例えば、データを破壊する可能性があります。
こういう場合、マイグレーションを戻せなければ、 down メソッドから IrreversibleMigration を raise 出来ます。
誰かがマイグレーションを元に戻そうとすると、エラーメッセージが表示され、それは行われません。

4 マイグレーションを走らせる(Running Migrations)

Rails はマイグレーションと動く rake タスクのセットを提供します、それは要約すると、マイグレーションの特定のセットを実行します。
マイグレーションに関連する、あなたが使う一番最初の rake タスクは、 db:migrate でしょう。
最も基本的な形式では、まだ実行されていない全てのマイグレーション内の up メソッドを実行します。
そのようなマイグレーションが存在しないなら、終了します。

db:migrate は、 db:schema:dump タスクを呼び出すことに注意して下さい。
それはデータベースの構造にマッチさせるために db/schema.rb ファイルを更新するでしょう。

ターゲットのバージョンを指定したら、Active Record は、必要なマイグレーション( up か down )を指定されたバージョンに達するまで実行するでしょう。
そのバージョンは、マイグレーションのファイル名の数値の接頭語です。
例えば、バージョン 20080906120000 への移行を実行するには、

rake db:migrate VERSION=20080906120000

現在のバージョンよりも大きい場合(すなわち、未来にマイグレーションするなら)、
これは 20080906120000 を含める、それより大きい全てのマイグレーションの up メソッドを実行するでしょう、
過去に移行するなら、それより小さい全てのマイグレーションの down メソッドを走らせますが、20080906120000を含めません。

4.1 ロールバック(Rolling Back)

よくあるタスクは、最後の移行をロールバックすることです。例えば、最後のマイグレーションでミスをして、それを修正したい場合です。
前のマイグレーションに関連付けられたバージョン番号を追跡するよりも、これで行えます。

rake db:rollback

これは、最新のマイグレーションの down メソッドを実行します。
いくつかのマイグレーションを元に戻す必要がある場合、 STEP パラメータを使うことが出来ます。

rake db:rollback STEP=3

最後の3つのマイグレーションから down メソッドを走らせるでしょう。

db:migrate:redo タスクは、ロールバックを行い、そして再度マイグレーションを実行するためのショートカットです。
一つ以上のバージョンを戻す必要がある場合、 db:rollback タスクに STEP パラメータを使うことが出来ます。
例えば

rake db:migrate:redo STEP=3

これらのRakeタスクのどちらも、 db:migrate で出来ないことではないですが、
マイグレーションのために明示的にバージョンを指定する必要が無いため、単純に便利です。

最後に、 db:reset タスクはデータベースを drop し、再度それを作り直し、現在のスキーマをそこにロードします。

これは、全てのマイグレーションを実行するのと、同じではありません。 - schema.rb のセクションを見てください。

4.2 指定する(Being Specific)

指定したマイグレーションの up や down を実行する必要があるとき、 db:migrate:up と、 db:migrate:down タスクがそれをするでしょう。
適切なバージョンを指定するだけで、対応するマイグレーションがその up や down メソッドを実行するでしょう。
例えば

rake db:migrate:up VERSION=20080906120000

は、20080906120000 マイグレーションから up メソッドを実行するでしょう。
これらのタスクは、マイグレーションが既に実行されたかどうかを確認します。
例えば、 20080906120000 は既に実行されたと Active Record が信じていれば、db:migrate:up VERSION=20080906120000 は何もしないでしょう。

4.3 おしゃべり(Being Talkative)

デフォルトでは、マイグレーションは、正確に何をしたかと、それにかかった時間を知らせます。
テーブルを作成し、インデックスを追加したマイグレーションは、このような出力を生成するでしょう。

20080906170109 CreateProducts: migrating
-- create_table(:products)
   -> 0.0021s
-- add_index(:products, :name)
   -> 0.0026s
20080906170109 CreateProducts: migrated (0.0059s) 

これを制御できるように、いくつかの方法が提供されています。

  • suppress_messages そのブロックによって生成されたすべての出力を抑制します。
  • say テキストを出力します。(インデントするかどうか、第二引数でコントロールする。)
  • say_with_time そのブロックを実行するに要した時間をテキストに出力します。ブロックが整数を返したら、影響を与えた行数とみなします。

例えば、このマイグレーション

class CreateProducts < ActiveRecord::Migration
  def self.up
    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

  def self.down
    drop_table :products
  end
end

は、以下の出力を生成します。

20080906170109 CreateProducts: migrating
  Created a table
   -> and an index!
  Waiting for a while
   -> 10.0001s
   -> 250 rows
 20080906170109 CreateProducts: migrated (10.0097s)

Active Recordを黙らせたいなら、rake db:migrate VERBOSE=false を実行すれば、いかなる出力も抑制されるでしょう。

5 マイグレーション内でモデルを使う(Using Models in Your Migrations)

マイグレーション内でデータを作成や更新するとき、あなたのモデルを使うのはしばしば魅力的です。
結局のところ、モデルは、元のデータへの簡単なアクセスを提供するために存在します。
使うことはできますが、いくつかの観察すべき注意点があります。

例として、対応しているテーブル内の行を更新するために、 Product モデルを使用しているマイグレーションを考えてみてください。
アリスは、新しいカラムと、それに対するバリデーションを追加する更新を Product モデルに最近しました。
ボブが休日から帰ってきて、ソースを更新し、 Product モデルを使った一つを含む未処理のマイグレーションを rake db:migrate で実行します。
マイグレーションを実行する時、ソースは最新なので、 Product モデルにはアリスによって加えられたバリデーションがあります。
しかしながら、データベースは古いままでそのカラムを持っておらず、結果としてエラーが起きるというのは、バリデーションはまだ存在していないカラム上にあるからです。

手作業でSQLを書くこと無しに、データベース内の行を更新したいことが、頻繁にあります:
モデルへの指定は使用しません。
このパターンの一つは、モデルのコピーをマイグレーション自身の中で定義することです。
例えば:

class AddPartNumberToProducts < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end

  def self.up
    ...
  end

  def self.down
    ...
  end
end

マイグレーションは Product モデル自身の最小限のコピーを持ち、アプリケーションで Product モデルが定義されているか気にしません。

5.1 モデルの変更に対応する(Dealing with Changing Models)

パフォーマンス上の理由から、モデルが持っているカラムについての情報は、キャッシュされています。
例えば、テーブルにカラムを追加して、新しい行を挿入するために対応するモデルを使おうとしても、古いカラムの情報を使おうとするでしょう。
reset_column_information メソッドを使うことにより、Active Record にカラム情報を再読み込みすることを強制できます。
例えば

class AddPartNumberToProducts < ActiveRecord::Migration
  class Product < ActiveRecord::Base
  end

  def self.up
    add_column :product, :part_number, :string
    Product.reset_column_information
    ...
  end

  def self.down
    ...
  end
end

6 スキーマのダンプ(Schema Dumping and You)

6.1 何のためのスキーマファイル?(What are Schema Files for?)

マイグレーションは、強力だけれど、データベーススキーマにとって権威あるソースではありません。
その役割は db/schema.rb と、 Active Record がデータベースを調べることにより生成したSQLファイルが該当します。
それらは編集されるように設計されておらず、ただデータベースの現在の状態を表しています。

マイグレーションの履歴全体を再生することによって、アプリの新しいインスタンスをデプロイする必要はありません。(それがエラーになりがちです)
現在のスキーマの説明をデータベースにロードするほうが、はるかに簡単でかつ速いです。

例えば、これは test データベースがどのように作られたかです。
現在の development データベースがダンプされ( db/schema.rb か db/development.sql )、testデータベースにロードされます。

また、Active Record オブジェクトがどのような属性を持っているかサッと見たい時に、スキーマファイルは有用です。
この情報は、モデルのコード上ではなく、頻繁にいくつかのマイグレーションを横断していますが、全ての情報がスキーマファイルに纏められています。
全てのモデルの一番上に自動的にスキーマ概要を追加(及び更新)する annotate_models プラグインは、興味深いでしょう。

6.2 スキーマのダンプの種類(Types of Schema Dumps)

スキーマをダンプする方法は二つあります。
これは、config/environment.rb 上の config.active_record.schema_format で :sql か :ruby に設定されます。

もし:rubyが選択されていれば、スキーマは db/schema.rb に格納されます。
このファイルを見れば、それが一つのとても大きいマイグレーションのような、巨大なものに見えることに気づくでしょう。

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"
    t.text     "description"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "part_number" 
  end
end

多くの点で、これは、まさしくそのものです。
このファイルは、データベースを調べることと、その構造を create_table 、 add_index を使って表現することによって作成されます。
これはデータベースに依存しないため、Active Record がサポートする任意のデータベースに読み込むことができます。
複数のデータベースに対して実行することができるアプリケーションを配布する場合、非常に有用かもしれません。

しかしながら、トレードオフもあります: db/schema.rb は外部キー制約やトリガー、ストアドプロシージャのようなデータベースの特定の項目は表現できません。
マイグレーションの中で、カスタムSQLステートメントを実行することができますが、スキーマのダンパーはデータベースからこれらのステートメントを再構築することはできません。
このような機能を使用している場合、スキーマのフォーマットを :sql に設定したほうがいいでしょう。

Active Record の、スキーマダンパを使用する代わりに、データベース固有のツールを使って、
データベースの構造は、 db/#{RAILS_ENV}_structure.sql 内に(Rakeタスクの db:structure:dump を介して)ダンプされるでしょう。
例えば、PostgreSQLにはpg_dumpユーティリティが、MySQLにはこのファイルは様々なテーブルのSHOW CREATE TABLEの出力が含まれるでしょう。
スキーマの読込は、単に内部に含まれたSQLステートメントを実行するだけの質問です。

定義では、これはデータベースの構造の完全なコピーですが、データベースを作成することに使われたものを別として、普通、スキーマのロードを防ぐでしょう。

6.3 スキーマダンプとソースコントロール(Schema Dumps and Source Control)

スキーマダンプは、データベーススキーマの信頼できるソースであるため、ソース管理にそれらを含めることを強く勧めます。

7 ActiveRecordと参照整合性(Active Record and Referential Integrity)

Active Record の方法によると、知能はデータベースでは無く、モデルに宿ります。
このように、データベースに知性を入れるトリガーや外部キー制約のような機能は、頻繁に使用されません。

validates_uniqueness_of のようなバリデーションは、モデルがデータの整合性を強制するための一つの方法です。
アソシエーション上の :dependent オプションは、親が破壊された時に自動的に子供のオブジェクトも破壊するようモデルに許可します。
アプリケーションレベルで動作するものと同様に、これらは参照整合性を保証することはできず、外部キー制約を増やす人もいます。

Active Record は直接そのような機能を使用するためのツールを提供していませんが、 execute メソッドは任意のSQLを実行するために使用できます。
Active Record に外部キー制約のサポート( db/schema.rb に外部キーをダンプするサポートを含む)を追加する redhillonrails のようなプラグインもいくつかあります。

8 Changelog

Lighthouse ticket

  • July 15, 2010: minor typos corrected by Jaime Iniesta
  • September 14, 2008: initial version by Frederick Cheung

コメント欄(誤訳・誤字があれば教えて頂ければ幸いです。)