In: Ruby / Rails| technology
6 5月 2008マイグレーション、やればやるほど便利ですね。
単純に、テーブル操作だけじゃなくて、ファイル保存先の変更とか、内部仕様の変更に対しても使えそうな印象を受けます。
基本的なやり方・書き方は、巷にあふれかえっていたので、そこは調べていただくとして。
今回は、特に、マイグレーションでの外部キーの設定の仕方について、メモ。
そもそも、マイグレーションってどうやるの?って人は、以下のところを参照されるとわかりやすいかと思います。
ひとつめのやり方として、外部キーの設定のところだけ、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
ユーザーがアップロードした画像を管理するテーブルのイメージでお願いします。
各ユーザーに画像のデータがぶら下がってる感じです。
とはいえ、こんなんじゃ、外部キーを設定しているのはわかるけど、いまいちわかりにくいですね。
それに、外部キーを設定するのはこれ一個とは限らないので、外部キーの設定のところだけ汎用化してしまいたいところです。
汎用化したいので、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とかになります。
これで、見た目直感的で、保守がしやすそうなソースになりましたね。
中には、それプラグインで、という人もいらっしゃるかと思われますので、ふたつめのやり方としてそちらをばご紹介。
結論から言えば、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:
ゆるーく、ふわーっと、興味のままに。
自分のかたわらに置いておくメモ代わり。