Last-modified: 2010-09-19 (日) 18:42:35 (4h)
Rails Database Migrations †
原文 †http://guides.rubyonrails.org/migrations.html マイグレーション(Migrations) †マイグレーションは、構造的で組織的な方法でデータベースを変更するための、便利な方法です。 Active Record は、どのマイグレーションが既に実行されたかを追跡しているので、やらなければならないのはソースを更新し rake db:migrate を実行することだけです。 マイグレーションはこれらの変換をRubyを使って記述することができます。 以下を含む移行のすべてについて学びます:
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 というテキストカラムを追加します。 マイグレーションは、スキーマを変更することだけに留まりません。 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 カラムを追加します。 マイグレーション内でモデルを使用する際に適用される注意点がいくつかあります。 1.1 マイグレーションはクラスです。(Migrations are Classes) †マイグレーションは ActiveRecord::Migration のサブクラスであり、2つのクラスのメソッドup(必要な変換を実行する)とdown(それらを元に戻す)を実装しています。 データベースに依存しない方法で、一般的なデータ定義のタスクを実行するメソッドを、Active Record は提供します。(詳細は後で読むことになるでしょう)
特定のタスクをデータベースに実行する必要があるなら(たとえば、外部キー制約を作成する) (PostgreSQLやSQLite3のように)スキーマを変更するステートメントのトランザクションをサポートしているデータベースでは 1.2 名前の意味は何?(What’s in a Name) †マイグレーションは db/migrate ファイルに、マイグレーションクラス毎に一つずつ格納されます。 内部的にRailsはマイグレーションの番号(タイムスタンプ)を識別するために使用するだけです。 config.active_record.timestamped_migrations = false タイムスタンプおよびマイグレーションの実行記録の組み合わせは、複数の開発者で発生する一般的な状況をRailsが処理できるようにします。 例えば、アリスが20080906120000と20080906123000のマイグレーションを追加し、ボブが20080906124500を追加して、実行するとしましょう。 もちろんこれは、チーム内のコミュニケーションの置き換えではありません。 1.3 マイグレーションを変更する(Changing Migrations) †場合によっては間違ったマイグレーションを書くかもしれません。 一般的に、既存のマイグレーションを編集することは良い考えではありません: 2 マイグレーションの作成(Creating a Migration) †2.1 モデルの作成(Creating a Model) †モデルと scaffold ジェネレータは、新しいモデルを追加するための適切なマイグレーションを作成します。 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 必要に応じるだけ、カラムの名前/型のペアを追加できます。 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"の形式にして、カラムの名前と型のリストを続ければ、 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のこと)により、テーブルにカラムを作成できます。 create_table :products do |t| t.column :name, :string, :null => false end 二番目の方式は、"sexy"マイグレーションと呼ばれていて、やや冗長な column メソッドを捨て去ります。 create_table :products do |t| t.string :name, :null => false end デフォルトでは cretae_table は id という主キーを作成します。
:primary_key オプションを使って、主キーの名前を変更できます(対応するモデルを更新するのを忘れないでください) create_table :products, :options => "ENGINE=BLACKHOLE" do |t| t.string :name, :null => false end は、テーブルを作成する際のSQL文に ENGINE=BLACKHOLE を追加するでしょう。(MySQLを使うとき、デフォルトは ENGINE=InnoDB ) Active Recordでサポートされている型は、 これらは、適切なデータベースの基本型にマッピングされるでしょう。 create_table :products do |t| t.column :name, 'polygon', :null => false end しかしながら、これは他のデータベースへの移植性を妨げることがあります。 3.2 テーブルの変更(Changing Tables) †cretae_table と似ていてるものに change_table があり、既存のテーブルを変更するために使用されます。 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 を加えます。 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つの特定のテーブルを変更するのに関連する全てのステートメントをグループ化します。 3.3 特別なヘルパ(Special Helpers) †Active Record は一般的な機能のために、いくつかのショートカットを提供します。 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 カラムを作るでしょう。 create_table :products do |t| t.references :attachment, :polymorphic => {:default => 'Photo'} end は、 attachment_id カラムを追加し、string型の attachment_type カラムを、デフォルト値 'Photo' で作るでしょう。 references ヘルパは、実際に外部キー制約を作成しません。 Active Record によって提供されるヘルパでは十分でない場合、任意のSQLを実行するための execute 関数を使えます。 個々のメソッドの詳細および例については、APIドキュメントを確認してください、 3.4 down メソッドを書く(Writing Your down Method) †マイグレーションの 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 時には、あなたのマイグレーションが不可逆な何かをするでしょう。 4 マイグレーションを走らせる(Running Migrations) †Rails はマイグレーションと動く rake タスクのセットを提供します、それは要約すると、マイグレーションの特定のセットを実行します。 db:migrate は、 db:schema:dump タスクを呼び出すことに注意して下さい。 ターゲットのバージョンを指定したら、Active Record は、必要なマイグレーション( up か down )を指定されたバージョンに達するまで実行するでしょう。 rake db:migrate VERSION=20080906120000 現在のバージョンよりも大きい場合(すなわち、未来にマイグレーションするなら)、 4.1 ロールバック(Rolling Back) †よくあるタスクは、最後の移行をロールバックすることです。例えば、最後のマイグレーションでミスをして、それを修正したい場合です。 rake db:rollback これは、最新のマイグレーションの down メソッドを実行します。 rake db:rollback STEP=3 最後の3つのマイグレーションから down メソッドを走らせるでしょう。 db:migrate:redo タスクは、ロールバックを行い、そして再度マイグレーションを実行するためのショートカットです。 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 タスクがそれをするでしょう。 rake db:migrate:up VERSION=20080906120000 は、20080906120000 マイグレーションから up メソッドを実行するでしょう。 4.3 おしゃべり(Being Talkative) †デフォルトでは、マイグレーションは、正確に何をしたかと、それにかかった時間を知らせます。 20080906170109 CreateProducts: migrating -- create_table(:products) -> 0.0021s -- add_index(:products, :name) -> 0.0026s 20080906170109 CreateProducts: migrated (0.0059s) これを制御できるように、いくつかの方法が提供されています。
例えば、このマイグレーション 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 モデルを使用しているマイグレーションを考えてみてください。 手作業で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) †パフォーマンス上の理由から、モデルが持っているカラムについての情報は、キャッシュされています。 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?) †マイグレーションは、強力だけれど、データベーススキーマにとって権威あるソースではありません。 マイグレーションの履歴全体を再生することによって、アプリの新しいインスタンスをデプロイする必要はありません。(それがエラーになりがちです) 例えば、これは test データベースがどのように作られたかです。 また、Active Record オブジェクトがどのような属性を持っているかサッと見たい時に、スキーマファイルは有用です。 6.2 スキーマのダンプの種類(Types of Schema Dumps) †スキーマをダンプする方法は二つあります。 もし: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 多くの点で、これは、まさしくそのものです。 しかしながら、トレードオフもあります: db/schema.rb は外部キー制約やトリガー、ストアドプロシージャのようなデータベースの特定の項目は表現できません。 Active Record の、スキーマダンパを使用する代わりに、データベース固有のツールを使って、 定義では、これはデータベースの構造の完全なコピーですが、データベースを作成することに使われたものを別として、普通、スキーマのロードを防ぐでしょう。 6.3 スキーマダンプとソースコントロール(Schema Dumps and Source Control) †スキーマダンプは、データベーススキーマの信頼できるソースであるため、ソース管理にそれらを含めることを強く勧めます。 7 ActiveRecordと参照整合性(Active Record and Referential Integrity) †Active Record の方法によると、知能はデータベースでは無く、モデルに宿ります。 validates_uniqueness_of のようなバリデーションは、モデルがデータの整合性を強制するための一つの方法です。 Active Record は直接そのような機能を使用するためのツールを提供していませんが、 execute メソッドは任意のSQLを実行するために使用できます。 8 Changelog †
コメント欄(誤訳・誤字があれば教えて頂ければ幸いです。) † |