bockdavidson
bockdavidson

Reputation: 2703

Rails ActiveRecord::InvalidForeignKey in ArticlesController#destroy

ActiveRecord::InvalidForeignKey in ArticlesController#destroy

SQLite3::ConstraintException: FOREIGN KEY constraint failed: DELETE FROM "articles" WHERE "articles"."id" = ?

I'm creating a blog app, I get this error every time I try to delete an article that has comments in it. How can I fix it?

Let me know what code to post and I will update the question.

Articles controller:

class ArticlesController < ApplicationController
    def new
        @article = Article.new
    end

    def index
     #@articles = Article.all
     @articles = Article.paginate(:page => params[:page], :per_page => 10)
    end

    def show
        @article = Article.find(params[:id])
    end

     def create
        @article = Article.new(article_params)

        @article.save
        redirect_to @article
    end

    def edit
        @article = Article.find(params[:id])
    end

    def update
        @article = Article.find(params[:id])
        if @article.update(article_params)
            redirect_to @article
        else
            render 'edit'
        end

    end

    def destroy
        @article = Article.find(params[:id])
        @article.destroy

        redirect_to articles_path
    end
end

private
def article_params
    params.require(:article).permit(:title, :text, :datee)
end

Articles model:

class Article < ApplicationRecord
    has_many :comments
    has_many :photos
end

Comment model:

class Comment < ApplicationRecord
  belongs_to :article
end

UPDATE

Now I have a new error

ArgumentError in ArticlesController#destroy

Unknown key: :dependant. Valid keys are: :class_name, :anonymous_class, :foreign_key, :validate, :autosave, :table_name, :before_add, :after_add, :before_remove, :after_remove, :extend, :primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache, :join_table, :foreign_type, :index_errors

Upvotes: 4

Views: 10945

Answers (3)

Ghis
Ghis

Reputation: 923

Additionally to the other correct answers :

In many scenarios, you may actually want to conserve the associated models and just delete the foreign key in the associated tables :

class Article < ApplicationRecord
  has_many :comments, dependent: :nullify
end

If you are building a blog module for instance, you are obligated by law to archive users comments for while before actual deletion. So you want to comply to it, I may as well suggest that you use a soft deletion system, such as paranoia, act_as_paranoid or discard :

class Article < ApplicationRecord
  act_as_paranoid

  # Not accurate, but here is approximatively what the gem does :
  # default_scope where(deleted_at: nil)

  has_many :comments, dependent: :delete_all # or :destroy if you have callbacks in Comment model

  def self.clean
    only_deleted.where('destroyed_at < ?', Date.today - 6.month).destroy_fully!
  end
end

This way, when you remove an article, the comments wont get destroyed, neither will the article itself. You can then setup some cron tasks (whenever) or delayed_job to perform the actual deletion after legal retention time passed :

# Whenever: schedule.rb
every 1.day, at: '4:30 am' do
  runner "Article.clean"
end

I did not test the code and it's a bit off topic, but I hope it helps.

Cheers !

Upvotes: 1

tenshiAMD
tenshiAMD

Reputation: 205

Using dependent: :delete_all does not use validation thus it is directly deleting records without validating properly. Use dependent: :destroy if you want your records to be validated safely.

class Article < ApplicationRecord
  has_many :comments, dependent: :destroy
end

Upvotes: 18

Gerry
Gerry

Reputation: 10507

To avoid this problem you could define dependent: :delete_all in Article model so every related Comment is also deleted, like this:

class Article < ApplicationRecord
  has_many :comments, dependent: :delete_all
end

Upvotes: 11

Related Questions