後からreferencesカラムを追加しようとするとdb:migrateできない

こんにちは!kossyです!





今回は1対多の関係を実現させる際に必要な外部キーを
設定し忘れた時の対処法をブログに残したいと思います。

ってかそんな大事なこと、設計の段階から気づけよって話なんですけど、人間忘れる生き物ですからね。(正当化)




環境
Rails 5.1.6
Ruby 2.5.1
MacOS Yosemite



状況はこうです。
(例)
1. userモデル、reviewモデル、commentモデル作成(user 1対多 review, review 1対多 comment)

2. マイグレファイル編集の際に、commentモデルに外部キーであるreview_idを記載するのを忘れる

3. rails db:migrateコマンドを実行。 その後忘れたことに気づく。

まぁrake db:rollbackで元に戻してもいいんですけど、後からいろいろマイグレファイルを実行した後に気がつくパターンもありますからね。

この場合は、普通にadd_columnで追加しようとしても、referencesが効きません。

(rails g migration Add_Review_id_To_Commentコマンドでできたマイグレファイルの中身)
以下の記述を追加
add_column :comment, :review_id,  :references, foreign_key: true

$ rails db:migrate

rails aborted!
StandardError: An error has occurred, all later migrations canceled:~~~(エラー文が続く)

そういうときは、

rails g migration ファイル名(キャメルorスネークケース) モデル名:references

(例) rails g migration Add_Review_id_To_Comment review:references

コマンドを実行しましょう。
すると、新たにマイグレファイルが生成されて、

(新しく作ったマイグレファイル)

def change
    add_reference :comment, :review, index: true
end

中身が上記のような記述になってます。

しかしこの記述のままrails db:migrateをしても外部キー制約が効かないらしいので、

def change
    add_reference :comment, :review, foreign_key: true(ここを変更)
end

これでrails db:migrateが通り、外部キー制約のついたカラムの生成に成功します。


参考にさせて頂いた記事

Railsの外部キー制約とreference型について - Qiita
add_reference来てた - 飲んだり寝たり
外部キーをreferences型カラムで保存する - Qiita
Ruby on Rails カラムの追加と削除 - Qiita