Edited at

rails5.2にアップデートしたら外部キーでマイグレーションが失敗するようになった


概要

rails5.0からrails5.2にバージョンを上げた時にマイグレーションが失敗するようになったので,原因の調査と解決を行なった.


原因

出力されたエラーは以下で,エラーを読むと,usersテーブルのidをmicropostsテーブルのuser_idの外部キーとして設定することに失敗したことが分かりました.


ActiveRecord::StatementInvalid: Mysql2::Error: Referencing column 'user_id' and referenced column 'id' in foreign key constraint 'fk_rails_558c81314b' are incompatible.: ALTER TABLE `microposts` ADD CONSTRAINT `fk_rails_558c81314b`
FOREIGN KEY (`user_id`)
REFERENCES `users` (`id`)

...
Caused by:
Mysql2::Error: Referencing column 'user_id' and referenced column 'id' in foreign key constraint 'fk_rails_558c81314b' are incompatible.

原因となっているusersテーブルとmicropostsテーブルのスキーマを調べたところ,userテーブルのidはbigint型,micropostsテーブルのuser_idはint型となっており,型が一致していませんでした.

これはrails5.1からテーブルのidカラムがbigintになったことによって起きたことでした.

mysql> show create table users \G;

*************************** 1. row ***************************
Table: users
Create Table: CREATE TABLE `users` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`password_digest` varchar(255) DEFAULT NULL,
`remember_digest` varchar(255) DEFAULT NULL,
`admin` tinyint(1) DEFAULT '0',
`activation_digest` varchar(255) DEFAULT NULL,
`activated` tinyint(1) DEFAULT '0',
`activated_at` datetime DEFAULT NULL,
`reset_digest` varchar(255) DEFAULT NULL,
`reset_sent_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `index_users_on_email` (`email`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> show create table microposts \G;
*************************** 1. row ***************************
Table: microposts
Create Table: CREATE TABLE `microposts` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`content` text,
`user_id` int(11) DEFAULT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NOT NULL,
`picture` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_microposts_on_user_id_and_created_at` (`user_id`,`created_at`) USING BTREE,
KEY `index_microposts_on_user_id` (`user_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)


解決策

今回は外部キーであるuser_idの型をbigintに変更することで対応しました.

具体的な対応としては,schema.rbを以下のように変更しました.

create_table "microposts", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|

...
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
...
end

create_table "microposts", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
...
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
...
end

この後,rails db:setupを実行することで,無事マイグレーションが成功するようになりました.


参考

こちらの記事を参考にさせていただきました.