M Alex
M Alex

Reputation: 139

I have this problem in Ruby on Rails SQLite3::ConstraintException: FOREIGN KEY constraint failed

I am new to Ruby on Rails. I try to make tags and have the option to delete the tag. When I want to destroy the tag, I get this error SQLite3::ConstraintException: FOREIGN KEY constraint failed.

ActiveRecord::InvalidForeignKey in TagsController#destroy

Here are my code for delete tag in controller:

def destroy
    @tag = Tag.find(params[:id])
    @tag.destroy

    flash.notice = "Tag '#{@tag.name}' Deleted!"
    
    redirect_to tags_path
end

This is the schema.rb

ActiveRecord::Schema.define(version: 2021_03_20_115719) do

  create_table "articles", force: :cascade do |t|
    t.string "title"
    t.text "body"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  create_table "comments", force: :cascade do |t|
    t.string "author_name"
    t.text "body"
    t.integer "article_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["article_id"], name: "index_comments_on_article_id"
  end

  create_table "taggings", force: :cascade do |t|
    t.integer "tag_id", null: false
    t.integer "article_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["article_id"], name: "index_taggings_on_article_id"
    t.index ["tag_id"], name: "index_taggings_on_tag_id"
  end

  create_table "tags", force: :cascade do |t|
    t.string "name"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

  add_foreign_key "comments", "articles"
  add_foreign_key "taggings", "articles"
  add_foreign_key "taggings", "tags"
end

Upvotes: 5

Views: 3185

Answers (1)

spickermann
spickermann

Reputation: 106792

A failed FOREIGN KEY constraint usually means that you have another record in your database that still has a belongs_to association set to this record and therefore you cannot delete it.

In your example, there is an article tagged with the tag you are trying to delete.

create_table "taggings", force: :cascade do |t|
  t.integer "tag_id", null: false        # << here the association
  t.integer "article_id", null: false

# in combination with

add_foreign_key "taggings", "articles"
add_foreign_key "taggings", "tags"       # << here the foreign key constraint

Your schema.rb shows that you have a taggings join table that connects articles with tags and in this table, both attributes (the tag_id and the article_id) cannot be nil and must contain a valid id that identifies a record on the associated table.

That means when you want to delete a specific tag then you have to remove the tag from the taggings join table first. The following code should work:

def destroy
  @tag = Tag.find(params[:id])
  @tag.articles.clear                    # << add this line
  @tag.destroy

  flash.notice = "Tag '#{@tag.name}' Deleted!"

  redirect_to tags_path
end

Read about collection.clear and the usage of the has_and_belongs_to association in general in the Rails Guides.

Upvotes: 11

Related Questions