- 更新日: 2014年3月9日
- Rails
Rails でデータベースに外部キー制約を設定する
Rails では、ActiveRecord デフォルトのマイグレーション機能では、外部キー制約を設定できません。公式のガイド(エントリー末尾参照)でも、execute で alter table の SQL を直接書いてあります。users テーブルの id カラムの外部キーとして user_id を使うと、自動で association の関係を作成はできますけど、外部キー制約(foreign key constraint)がデータベースに設定されることはない。
— 環境 —
rails 4.0.1
mysql 5.5.28
foreign key constraint(外部キー制約)を設定するには、自力で生の SQL を利用するか、あるいは foreigner という gem を利用するかの二通りの方法があるようです。今回は、自力で SQL を使って外部キー制約を設定する方法を用いました。
外部キー制約のためのヘルパー作成
毎回生SQLを書くのは辛いので、以下のようなヘルパーを作成しました。
lib/migration_helper.rb
1 2 3 4 5 6 7 8 9 10 11 12 |
module MigrationHelper def set_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 def remove_foreign_key(from_table, to_table) constraint_name = "fk_#{from_table}_#{to_table}" execute "alter table #{from_table} drop foreign key #{constraint_name};" end end |
一応、外部キー制約を削除する remove_foreign_key も作成しましたけど、試したところ、マイグレーションの self.down でこれを単独で利用すると、rollback が上手く働かないことがありました。
以下のようなマイグレーションは、rollback で self.down が動かないケースが発生したので、このような使い方はしないようにする。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
require 'migration_helper' class AddForeignKeyToPosts < ActiveRecord::Migration extend MigrationHelper def self.up set_foreign_key :posts, :user_id, :users end def self.down remove_foreign_key posts, users end end |
create_table と同時に set_foreign_key
なので、remove_foreign_key のほうは使わずに、create_table のマイグレーションで同時に set_foreign_key を呼び出し、その self.down で drop_table する方法を採用しました。
以下のように create_table 時に同時に foreign key をセットし、rollback(self.down)では drop_table。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
require 'migration_helper' class CreatePosts < ActiveRecord::Migration extend MigrationHelper def self.up create_table :posts do |t| t.string :comment, null: false, default: "" t.integer :user_id, null: false t.timestamps end add_index :posts, [:user_id, :created_at] set_foreign_key :posts, :user_id, :users end def self.down drop_table :posts end end |
MySQL で外部キー制約を確認
マイグレーションを実行後、データベース(MySQL)を確認してみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
mysql> show create table posts; +----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Table | Create Table | +----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | posts | CREATE TABLE `posts` ( `id` int(11) NOT NULL AUTO_INCREMENT, `comment` varchar(255) NOT NULL DEFAULT '', `user_id` int(11) NOT NULL, `created_at` datetime DEFAULT NULL, `updated_at` datetime DEFAULT NULL, PRIMARY KEY (`id`), KEY `index_posts_on_user_id_and_created_at` (`user_id`,`created_at`), CONSTRAINT `fk_posts_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 | +----------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 1 row in set (0.00 sec) |
1 2 3 |
CONSTRAINT `fk_posts_users` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) |
の行で、fk_posts_users という名前で、users テーブルの id カラムを参照する posts テーブルの user_id に対して、外部キー制約が設定されているのを確認できます。
- – 参考リンク –
- Active Record Migrations — Ruby on Rails Guides
- マイグレーションで外部キーを設定する2通りの方法 – Katawara.*
- Ruby on Railsで外部キー設定 – 戯言メイテル
- Rails の関連記事
- RailsでMySQLパーティショニングのマイグレーション
- Rails ActiveRecordでdatetime型カラムのGROUP BY集計にタイムゾーンを考慮する
- RailsプラグインGemの作成方法、RSpecテストまで含めたrails pluginの作り方
- RailsでAMPに対応するgemをリリースしました
- Railsでrequest.urlとrequest.original_urlの違い
- Railsでwheneverによるcronバッチ処理
- Google AnalyticsのRails Turbolinks対応
- Railsアプリにソーシャル・シェアボタンを簡単設置
- Rails監視ツール用にErrbitをHerokuで運用
- Facebook APIバージョンのアップグレード手順(Rails OmniAuth)
Leave Your Message!