Reputation: 2703
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
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
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
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