【Rails】raise(ArgumentError, “Table ‘#{from_table}’ has no foreign key for #{to_table || options}”)の対処法

Railsのマイグレーションファイルでテーブルの関連付けを修正していたところ、raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")というエラーに遭遇したので原因と対処法をまとめます。

※開発環境にはDockerを使っています。

バージョン
  • Ruby 3.2.2
  • Rails 7.1.2
記事の信頼性
  • 独学で未経験から従業員300名以上の自社開発企業へ転職しました。
  • 実務ではVue.jsとRailsを毎日書いています。
  • 初心者や駆け出しエンジニアがつまづくポイントも身をもってよく理解しています。
目次

問題

以下のマイグレーションファイルを実行したところ、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も問題なさそうです!

おわりに

雰囲気で使わずに、きちんと公式ドキュメントを確認することが大切ですね。

参考文献
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

未経験でSESから従業員300名以上の自社開発企業に転職しました。業務や個人開発で直面した問題や、転職・学習の経験を発信していきます。

コメント

コメントする

目次