マイグレーション、やればやるほど便利ですね。
単純に、テーブル操作だけじゃなくて、ファイル保存先の変更とか、内部仕様の変更に対しても使えそうな印象を受けます。
基本的なやり方・書き方は、巷にあふれかえっていたので、そこは調べていただくとして。
今回は、特に、マイグレーションでの外部キーの設定の仕方について、メモ。
マイグレーション、基礎
そもそも、マイグレーションってどうやるの?って人は、以下のところを参照されるとわかりやすいかと思います。
- RoR Wiki 翻訳 Wiki - UnderstandingMigrations
- RoR Wiki 翻訳 Wiki - UsingMigrations
- ヽ( ・∀・)ノくまくまー(2005-08-17)
- Rails Wiki - migration
- FFTT : RailsのMigration
1 : SQLを利用する場合
ひとつめのやり方として、外部キーの設定のところだけ、SQLで呼び出すやり方があります。
たとえば、こんな感じ。
-
def self.up
-
options = {
-
:force => true,
-
:options => "ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;"
-
}
-
create_table(:images, options) do |t|
-
t.column(:user_id, :integer, :null => false)
-
t.column(:image, :string, :null => false)
-
t.column(:comment, :text)
-
t.column(:created_at, :timestamp)
-
t.column(:updated_at, :timestamp)
-
end
-
execute "alter table images add constraint fk_images_users foreign key (user_id) references users(id)"
-
end
ユーザーがアップロードした画像を管理するテーブルのイメージでお願いします。
各ユーザーに画像のデータがぶら下がってる感じです。
とはいえ、こんなんじゃ、外部キーを設定しているのはわかるけど、いまいちわかりにくいですね。
それに、外部キーを設定するのはこれ一個とは限らないので、外部キーの設定のところだけ汎用化してしまいたいところです。
1' : SQLを利用する場合・改
汎用化したいので、libフォルダ直下に、新しくヘルパー用のクラスを作ってしまいます。
参照元の丸パクリで恐縮ですが、MigrationHelperというクラス名で作ってみましょう。
-
module MigrationHelper
-
-
# 外部キー作成メソッド.
-
# migrationで外部キーを実行する場合のSQLを見えないようにして、migrationファイルの可視性アップを狙う.
-
def foreign_key(from_table, from_column, to_table)
-
constraint_name = "fk_#{from_table}_#{to_table}"
-
-
execute "alter table #{from_table} add constraint #{constraint_name} foreign key (#{from_column}) references #{to_table}(id)"
-
end
-
-
end
で、さっきのマイグレーション用のクラスのソースをこう直します。
-
require 'migration_helper'
-
class CreateImages <ActiveRecord::Migration
-
-
# 外部キー用のモジュールを使えるように拡張する.
-
extend MigrationHelper
-
-
# imagesテーブルを作成する.
-
def self.up
-
options = {
-
:force => true,
-
:options => "ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;"
-
}
-
create_table(:images, options) do |t|
-
t.column(:user_id, :integer, :null => false)
-
t.column(:image, :string, :null => false)
-
t.column(:comment, :text)
-
t.column(:created_at, :timestamp)
-
t.column(:updated_at, :timestamp)
-
end
-
foreign_key(:images, :place_id, :places)
-
end
-
-
# imagesテーブルを削除する.
-
def self.down
-
drop_table :images
-
end
-
end
注意するのは、requireとextendのところを忘れないこと。
でないと、NoMethodErrorとかになります。
これで、見た目直感的で、保守がしやすそうなソースになりましたね。
2 : プラグインを利用する場合
中には、それプラグインで、という人もいらっしゃるかと思われますので、ふたつめのやり方としてそちらをばご紹介。
結論から言えば、Foreign Key Migrationsというプラグインがございます。
これは、詳しくはリンク先のページ(英語)もしくは、日本語訳されてるこちらを当たってもらえればと思いますが、railsの規約に沿っていれば、外部キーの設定は書かなくても、勝手に外部キーの設定もするよ、というステキプラグインです。
なので、さっきのソースで行くと、これだけで同じことができてしまいます。
-
def self.up
-
options = {
-
:force => true,
-
:options => "ENGINE = InnoDB CHARACTER SET utf8 COLLATE utf8_general_ci;"
-
}
-
create_table(:images, options) do |t|
-
t.column(:user_id, :integer, :null => false)
-
t.column(:image, :string, :null => false)
-
t.column(:comment, :text)
-
t.column(:created_at, :timestamp)
-
t.column(:updated_at, :timestamp)
-
end
-
end
ちなみに、このプラグイン。
Foreign Key MigrationsとRedHill on Rails Coreという二つのプラグインをインストールしないと動きませんので、インストールする場合はご注意ください。
また、使ってみてわかりましたが、テーブルをdropしようとすると、エラーになってうまく消せないみたいです。
(※ただし、MySQL Administratorとかのアプリからdropする分には、何も問題がありません)
原因を深く追いかけなかったのでアレなんですけど、スキーマをダウングレードするのもちゃんとできなきゃイヤ! って人には向かないかと思われます。。
個人的には
1'のやり方が一番しっくり来ますね。
何でもかんでもプラグイン頼みしてしまうのは、それだけブラックボックスなソースを受け入れることでもあるし、考え物なのかもな、と、この一件で思ってしまったので。。。
Via:

0 Responses to “マイグレーションで外部キーを設定する2通りの方法”