- 更新日: 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)

 画像付き英語辞書 Imagict | 英単語をイメージで暗記
画像付き英語辞書 Imagict | 英単語をイメージで暗記









Leave Your Message!