🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

Q&A

解決済

1回答

7309閲覧

ユーザーをデータベースから削除できない。InvalidForeignKey、FOREIGN KEY constraint failedのエラー

punchan36

総合スコア105

Ruby on Rails 5

Ruby on Rails 5は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

データベース

データベースとは、データの集合体を指します。また、そのデータの集合体の共用を可能にするシステムの意味を含めます

0グッド

0クリップ

投稿2021/01/11 05:39

編集2021/01/12 12:26

前提・実現したいこと

ユーザーをデータベースから削除しようとしましたが、「Invalid Foreign Key」のエラーが出て削除が出来ません。

ユーザーはUserテーブルを介して、他の複数のテーブルと「多対多」ないし「1対多」の関係で結びついています。
調べてみた所、以下の内容が原因かと思いました。
「該当のユーザーが削除された際に、例えばユーザーの主キーを参照する他テーブルのデータは参照先を持たないデータとなってしまう。」

ですので全てのテーブルに関して、has_many (ないしhas_one)に対してdependent: :destroy の書き忘れがないかを見直し、ない部分には書き足しました。
しかし該当のエラーが変わらず出てきます…。どのように対応すれば宜しいでしょうか。
ご助言を頂けますと有難いです。

発生している問題・エラーメッセージ

[12] pry(main)> User.find(20).destroy ... #省略。該当のユーザーが関わっているアソシエーション関連の情報の読み込み。 ActiveRecord::InvalidForeignKey: SQLite3::ConstraintException: FOREIGN KEY constraint failed: DELETE FROM "users" WHERE "users"."id" = ? from C:/Users/hoge/vendor/bundle/ruby/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/statement.rb:108:in `step' Caused by SQLite3::ConstraintException: FOREIGN KEY constraint failed from C:/Users/hoge/vendor/bundle/ruby/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/statement.rb:108:in `step'

試したこと

  1. 試しにユーザーを新規作成し、何のアクションもしないままユーザーの削除を試みると上手く削除出来ました。

  2. 本アプリにはフォロー、投稿、コメント、いいね、メッセージ、通知機能などあるのですが、何かしらのアクションを起こした(また他ユーザーから起こされた)後だと削除が出来なくなります。やはり外部キーに問題があるようです。

  3. 「ある該当のアクションを行うとユーザーの削除が出来なくなる」のではなく「基本的に何でもアクションを行う(される)と削除が出来なくなる」現象が起こっています。

あらゆるアクションに共通して絡んでいるのは通知機能であるNotificationsテーブルですので、こちらが怪しいのではと踏んだのですが、以下の理由からそれもどうやら違うようです。

メッセージ機能において、ユーザーがトークルーム(Room, Entryテーブル)を作成するアクションがあってからメッセージのやり取りが出来るようになるのですが、このアクション自体は相手に通知がいきません。
試しに「新規ユーザーA」を作成し、他のユーザーが「ユーザーA」とのトークルームを作った(メッセージの送信はしていない)段階で「ユーザーA」の削除を試みました(ユーザーAは何のアクションもしていない)。
しかしこれでも削除が出来なかったので、通知が絡んでいる・いないは関係ないようです…。

4. 最後にモデルの関連付けを全てコメントアウトしてからユーザーの削除を試みましたが、それでも全く同じエラーが出ました。

補足情報(FW/ツールのバージョンなど)

ruby 2.6.4p104
RubyGems 3.0.3
Rails 5.2.3

追記

rails db:schema:dumpを行いschema.rbを最新のものにしました。
また追記により文字数制限を超えてしまったので、前回載せていた古い方のschema.rbを削除しました。

C:\Users\hoge\app\アプリ名>rails db:schema:dump (0.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC ↳ bin/rails:4

schema.rb

ActiveRecord::Schema.define(version: 2021_01_08_054626) do create_table "active_storage_attachments", force: :cascade do |t| t.string "name", null: false t.string "record_type", null: false t.integer "record_id", null: false t.integer "blob_id", null: false t.datetime "created_at", null: false t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true end create_table "active_storage_blobs", force: :cascade do |t| t.string "key", null: false t.string "filename", null: false t.string "content_type" t.text "metadata" t.bigint "byte_size", null: false t.string "checksum", null: false t.datetime "created_at", null: false t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true end create_table "comments", force: :cascade do |t| t.integer "user_id" t.integer "post_id" t.text "body" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "entries", force: :cascade do |t| t.integer "user_id" t.integer "room_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["room_id"], name: "index_entries_on_room_id" t.index ["user_id"], name: "index_entries_on_user_id" end create_table "goings", force: :cascade do |t| t.integer "user_id" t.integer "post_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "languages", force: :cascade do |t| t.string "description" t.boolean "done" t.integer "user_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["user_id"], name: "index_languages_on_user_id" end create_table "likes", force: :cascade do |t| t.integer "user_id" t.integer "post_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "messages", force: :cascade do |t| t.integer "user_id" t.integer "room_id" t.text "content" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["room_id"], name: "index_messages_on_room_id" t.index ["user_id"], name: "index_messages_on_user_id" end create_table "notifications", force: :cascade do |t| t.integer "visitor_id", null: false t.integer "visited_id", null: false t.integer "post_id" t.string "action", default: "", null: false t.boolean "checked", default: false, null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "comment_id" t.integer "message_id" t.integer "room_id" t.boolean "read", default: false, null: false t.index ["comment_id"], name: "index_notifications_on_comment_id" t.index ["message_id"], name: "index_notifications_on_message_id" t.index ["post_id"], name: "index_notifications_on_post_id" t.index ["room_id"], name: "index_notifications_on_room_id" t.index ["visited_id"], name: "index_notifications_on_visited_id" t.index ["visitor_id"], name: "index_notifications_on_visitor_id" end create_table "posts", force: :cascade do |t| t.string "title" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "user_id" t.string "message" t.string "level" t.integer "maximum" t.string "post_image_name" t.string "language" t.date "date" t.time "time" t.datetime "closing_time" end create_table "relationships", force: :cascade do |t| t.integer "follower_id" t.integer "following_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["follower_id", "following_id"], name: "index_relationships_on_follower_id_and_following_id", unique: true t.index ["follower_id"], name: "index_relationships_on_follower_id" t.index ["following_id"], name: "index_relationships_on_following_id" end create_table "rooms", force: :cascade do |t| t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false end create_table "user_languages", force: :cascade do |t| t.integer "user_id" t.integer "language_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["language_id"], name: "index_user_languages_on_language_id" t.index ["user_id"], name: "index_user_languages_on_user_id" end create_table "users", force: :cascade do |t| t.string "name" t.string "email" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "image_name" t.string "password_digest" t.string "cover_image_name" t.string "sex" t.string "country" t.string "language" t.text "introduction" end end

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2021/01/11 05:55

schema.rbにadd_foreign_keyの定義はありませんか?
punchan36

2021/01/11 06:06

有難うございます。 schema.rbは載せている記述が全てでして、そちらは定義しておりません…。
winterboum

2021/01/12 08:11

「モデルの関連付けを全てコメントアウト」全てのモデルの全ての関連ですか?
punchan36

2021/01/12 08:14

はい。 全12テーブル全て、最初のclass~~の1行と最後のendを除き全てコメントアウトした上でユーザーの削除を試みましたが、ダメでした。
winterboum

2021/01/12 08:55

念の為 schema.rbを最新にしてください。 rails db:schema:dump して db/shecme.rb を貼り替えてください。
punchan36

2021/01/12 09:42

有難うございます。 C:\Users\hoge\app\アプリ名>rails db:schema:dump (0.4ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC ↳ bin/rails:4 このようになり、その後でユーザーの削除を試みましたが同じ結果になりました…。
winterboum

2021/01/12 10:39

いや、最新の schema.rbを確認したいので、dumpしたあと貼り直してください
punchan36

2021/01/12 12:28

失礼致しました。最新のschema.rbを追記致しました。 ただ以下の様に日付が古いままになっております。コマンドでdumpした際の内容も追記致しましたが、これはちゃんと更新されているのでしょうか…? ActiveRecord::Schema.define(version: 2021_01_08_054626) do
punchan36

2021/01/17 01:04

お二方とも有難うございました。その後無事自己解決致しました。 データベースをSQLite3からMySQLに変えた事で、schema.rbにadd_foreign_keyの定義も表示されました。詳細は回答に記載致しました。
guest

回答1

0

自己解決

あるモデルの has_manyの記述の中で、複数形の「s」が抜けていた事が原因でした。
うっかりミスでした…。

has_many :user_language, dependent: :destroy has_many :languages, through: :user_language

has_many :user_languages, dependent: :destroy has_many :languages, through: :user_languages

また、以下の手順によりここに問題がある事をを突き止める事が出来ました。

データベースはSQLite3を使用していたのですが、この問題はSQLite3特有のエラーである可能性も否定出来ないと思い、MySQLに変えてみる事にしました。

結局MySQLに変えても同じようにエラーが出たのですが、SQLite3の時とはエラー文の記述が異なっていました。

SQlite3使用時のエラー文

ActiveRecord::InvalidForeignKey: SQLite3::ConstraintException: FOREIGN KEY constraint failed: DELETE FROM "users" WHERE "users"."id" = ? from C:/Users/hoge/vendor/bundle/ruby/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/statement.rb:108:in `step' Caused by SQLite3::ConstraintException: FOREIGN KEY constraint failed from C:/Users/hoge/vendor/bundle/ruby/2.6.0/gems/sqlite3-1.4.2/lib/sqlite3/statement.rb:108:in `step'

MySQL使用時のエラー文

ActiveRecord::StatementInvalid: Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`hoge_development`.`user_languages`, CONSTRAINT `fk_rails_db4f7502c2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)): DELETE FROM `users` WHERE `users`.`id` = 2 from C:/Users/hoge/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3-x64-mingw32/lib/mysql2/client.rb:131:in `_query' Caused by Mysql2::Error: Cannot delete or update a parent row: a foreign key constraint fails (`hoge_development`.`user_languages`, CONSTRAINT `fk_rails_db4f7502c2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`)) from C:/Users/hoge/vendor/bundle/ruby/2.6.0/gems/mysql2-0.5.3-x64-mingw32/lib/mysql2/client.rb:131:in `_query'

この様にテーブルの情報まで言及してくれていた為、これを見る事でuser_languagesの辺りがおかしいのではないかと予測し、問題を発見する事が出来ました。

またMySQLに変えると、schema.rbの最後の行にSQLite3使用時にはなかったadd_foreign_keyに関する記述も追加されました。

schema.rb

add_foreign_key "entries", "rooms" add_foreign_key "entries", "users" add_foreign_key "languages", "users" add_foreign_key "messages", "rooms" add_foreign_key "messages", "users" add_foreign_key "user_languages", "languages" add_foreign_key "user_languages", "users"

このように整理される事で「おかしいキーはこのうちのどれだろう」と考える事も出来たので、その点も良かったです。
今後は本番環境も考え、取りあえずMySQLを使用していこうかと思います。

投稿2021/01/17 01:02

punchan36

総合スコア105

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問