Railsのマイグレーションファイルでテーブルの関連付けを修正していたところ、raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
というエラーに遭遇したので原因と対処法をまとめます。
※開発環境にはDockerを使っています。
問題
以下のマイグレーションファイルを実行したところ、raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
というエラーが発生しハマりました。
class ChangeBookmarkRelations < ActiveRecord::Migration[7.1]
def change
remove_reference :bookmarks, :users, index: true, foreign_key: true
add_reference :bookmarks, :employees, null: false, foreign_key: true
end
end
Bookmarkテーブルが現時点ではUserテーブルとPostテーブルの中間テーブルとなっているんですが、この関連付けを変更したかったです。
Userテーブルではなく、EmployeeテーブルとPostテーブルを関連づける必要がありました。
ところがマイグレーションファイル実行すると次のようなエラーが出てしまいます、、。
$ docker compose run --rm web rails db:migrate
[+] Running 1/0
✔ Container sample-api-db-1 Running 0.0s
== 20240117232958 ChangeBookmarkRelations: migrating ==========================
-- remove_reference(:bookmarks, :users, {:index=>true, :foreign_key=>true})
bin/rails aborted!
StandardError: An error has occurred, all later migrations canceled: (StandardError)
Table 'bookmarks' has no foreign key for users
/sample-api/db/migrate/20240117232958_change_bookmark_relations.rb:3:in `change'
Caused by:
ArgumentError: Table 'bookmarks' has no foreign key for users (ArgumentError)
raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/sample-api/db/migrate/20240117232958_change_bookmark_relations.rb:3:in `change'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
解決方法
remove_reference
メソッドの第2引数に参照先を指定していますが、これがusers
と複数形になっているのが原因でした。
マイグレーションファイルを以下のように修正することでrails db:migrate
が成功しました。
※なおadd_references
メソッドの第2引数のemployees
も複数形でしたが、こっちも単数形じゃないとダメなので合わせて修正しています。
# users と employees を単数形に変更
class ChangeBookmarkRelations < ActiveRecord::Migration[7.1]
def change
remove_reference :bookmarks, :user, index: true, foreign_key: true
add_reference :bookmarks, :employee, null: false, foreign_key: true
end
end
これでマイグレーションファイルを実行すると、、、
$ docker compose run --rm web rails db:migrate
[+] Running 1/0
✔ Container sample-api-db-1 Running 0.0s
== 20240117232958 ChangeBookmarkRelations: migrating ==========================
-- remove_reference(:bookmarks, :user, {:index=>true, :foreign_key=>true})
-> 0.0303s
-- add_reference(:bookmarks, :employee, {:null=>false, :foreign_key=>true})
-> 0.0688s
== 20240117232958 ChangeBookmarkRelations: migrated (0.0993s) =================
無事にrails db:migrate
が実行できました!
ロールバックできるかも確認してみます。
$ docker compose run --rm web rails db:rollback
[+] Running 1/0
✔ Container sample-api-db-1 Running 0.0s
== 20240117232958 ChangeBookmarkRelations: reverting ==========================
-- remove_reference(:bookmarks, :employee, {:null=>false, :foreign_key=>true})
-> 0.0422s
-- add_reference(:bookmarks, :user, {:index=>true, :foreign_key=>true})
-> 0.0421s
== 20240117232958 ChangeBookmarkRelations: reverted (0.0881s) =================
rails db:rollback
も問題なさそうです!
おわりに
雰囲気で使わずに、きちんと公式ドキュメントを確認することが大切ですね。
コメント