Rails Migration
Migrationは物理的なデータベースによって使われるスキーマの変更を 管理するためのものです。新しい機能のために、 データベースにフィールドを追加する必要がある時 他の開発者にどのように変更を伝えるか、 商用サーバにそれをどう適用すればよいかを 伝えるための共通の問題に対するソリューションです。 Migrationを使う事で、変更をクラスとして記述する事ができ、 バージョン管理システムで管理し、他のデータベースに対して 1、2または5つ以上のバージョンを適用することができます。
Migrationの簡単な例は次のようにものです:
class AddSsl < ActiveRecord::Migration def self.up add_column :accounts, :ssl_enabled, :boolean, :default => 1 end def self.down remove_column :accounts, :ssl_enabled end end
このMigrationはaccountテーブルにbooleanのフラグを追加し、 Migrationを戻すとそのフラグを削除するものです。 これは全てのMigrationが、移行に必要な実装/削除に必要な変更を記述するため、 2つのクラスメソッドupとdownを持つことを示しています。 これらのメソッドは、migrationのメソッドであるadd_columnやremove_columnだけでなく、 変更に必要なデータを生成するための通常のRubyコードを含む事ができます。
データの初期化が必要な場合のもう少し複雑なmigrationの例は次のようになります:
class AddSystemSettings < ActiveRecord::Migration def self.up create_table :system_settings do |t| t.column :name, :string t.column :label, :string t.column :value, :text t.column :type, :string t.column :position, :integer end SystemSetting.create :name => "notice", :label => "Use notice?", :value => 1 end def self.down drop_table :system_settings end end
このMigrationは最初にsystem_settingテーブルを追加し、 ActiveRecordモデルを利用して最初の行を作成しています。 また、これは完全なテーブルスキーマをブロックコールで作成する、 create_tableのより高度な文法を使用しています。
使用可能な変換
create_table(name, options)
:nameというテーブルを作成し、 ブロックでadd_columnと同じフォーマットで列を作成できるようにします。 上記の例を参照してください。このoptionsハッシュはDEFAULT CHARSET="UTF-8"のような フラグメントをcreate tableの定義に追加するためのものです。drop_table(name)
:nameテーブルをdropします。rename_table(old_name, new_name)
:old_nameというテーブルを new_nameにリネームします。add_column(table_name, column_name, type, options)
: table_nameというテーブルにcolumn_nameという名前の新しい列を追加します。 typeは以下のタイプです:
:string、:text、:integer、:float、:decimal、:datetime、:timestamp、:time、:date、:binary、 :boolean。
デフォルト地はoptionsハッシュに{:default => 11}のようにして追加できます。 ほかにも:limitや:null(例えば
{ :limit => 50, :null => false}
)を追加できます。 詳しくはActiveRecord::ConnectionAdapters::TableDefinition#columnを参照してください。rename_column(table_name, column_name, new_column_name)
: 列をリネームします。タイプと内容は保持します。change_column(table_name, column_name, type, options)
: add_columnと同じパラメータで、列を別のタイプに変更します。remove_column(table_name, column_name)
:table_nameという名前の テーブルからcolumn_nameという列を削除します。add_index(table_name, column_names, index_type, index_name)
: 新しいインデックスを列名または(もし指定されていれば)index_nameをつかって作成する。 index_type(例えばUNIQUE)も指定できる。remove_index(table_name, index_name)
: index_nameで指定したindexを削除する。
復元不可能な変更
いくつかの変更は戻す事のできない破壊的なものがあります。 そのようなのMigrationはdownメソッドで IrreversibleMigration例外をraiseするべきです。
RailsからMigrationを実行する
RailsはMigrationを作ったり適用するのを助けるいくつかのツールを持っています。
新しいMigrationを作るには、script/generate migration MyNewMigration
を使います。ここでMyNewMigrationはこのMigrationの名前です。
このジェネレータはnnn_my_new_migration.rbというファイルをdb/migrate/ディレクトリに
作成します。nnnはmigration番号です。n個のMyNewMigrationのself.upとself.downメソッドを
書き換える事になるでしょう。
現在設定されているデータベースに対してMigrationを実行するには
rake migrate
を実行します。このコマンドは全ての未実行の
migrationを実行してデータベースを更新し、もし存在しなければschema_infoテーブルを
作成します。
データベースを前のmigrationバージョンにロールバックするには
rake migrate VERSION=X
を実行します。
Xはダウングレードしたいバージョンの番号です。
もしmigrationがIrreversibleMigration例外をスローした場合
そのステップは手作業で行う必要があります。
データベースサポート
Migrationは現在MySQL, PostgreSQL, SQLite、SQL Server、 Sybase、そしてOracleを サポートしています。
サンプル
全てのmigrationがスキーマを変更するとは限りません。 データを修正するものもあります:
class RemoveEmptyTags < ActiveRecord::Migration def self.up Tag.find(:all).each { |tag| tag.destroy if tag.pages.empty? } end def self.down # not much we can do to restore deleted data raise IrreversibleMigration end end
他にはdownではなくupの時に列を削除することもあります:
class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration def self.up remove_column :items, :incomplete_items_count remove_column :items, :completed_items_count end def self.down add_column :items, :incomplete_items_count add_column :items, :completed_items_count end end
そして、直接SQLを実行したい場合は
class MakeJoinUnique < ActiveRecord::Migration def self.up execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)" end def self.down execute "ALTER TABLE `pages_linked_pages` DROP INDEX `page_id_linked_page_id`" end end
テーブルを変えた後にそのモデルを使う場合
しばしばMigrationで列を追加して、その直後にデータを設定したい場合があるでしょう。 その場合、新しい列を追加した後、モデルにその列がある事を保証するために Base#reset_column_informationを呼ぶ必要があります。例えば:
class AddPeopleSalary < ActiveRecord::Migration def self.up add_column :people, :salary, :integer Person.reset_column_information Person.find(:all).each do |p| p.update_attribute :salary, SalaryCalculator.compute(p) end end end
詳細の制御
デフォルトでは、Migrationは、なにを行ったかを各ステップにどのくらいかかったかの ベンチマークとともにコンソールに出力することで表します。
ActiveRecord::Migration.verbose = falseとすることでそれらを抑制する事ができます。
また、say_with_timeメソッドを使ってベンチマークに独自のメッセージを 挿入することができます:
def self.up ... say_with_time "Updating salaries..." do Person.find(:all).each do |p| p.update_attribute :salary, SalaryCalculator.compute(p) end end ... end
"Updating salaries..."がブロックが終わったときのベンチマークとともに出力されます。
0 件のコメント:
コメントを投稿