我正在创建一个Blog应用程序,我正在尝试在用户控制器中编写destroy方法来处理用户被销毁时的情况。我希望它触发删除所有相关对象的操作,但是当我指定"依赖:: destroy"在模型中,我得到N + 1个查询(或N * M,如果那可能......) - 每一篇文章都被逐一删除,然后是所有评论,所有标签,所有标签(表格到处理HABTM关系)。
我曾尝试编写服务对象以摆脱这个长查询,但我无法使其工作,因为我违反了外键约束"。 这里有什么可能性?我不想在我的数据库中允许nils只是为了能够通过运行在DB中查找nils的查询来轻松清理数据库(以避免用户输入奇怪的内容),因此依赖:: nullify赢了在这里工作......如果可能的话,我也不愿使用Callbacks。
在选择带有服务的解决方案时,我首先等待用户被删除,然后调用服务来清理Orhpans,但是当代码执行错误时,我最终会遇到nils - 我应该使用交易吗?在这?
用户可以是文章的作者,该文章被标记,可以被其他用户评论。
以下是主要课程:
用户:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_many :articles, foreign_key: 'author_id'
has_many :comments, foreign_key: 'author_id'
validates :email, presence: true
end
文章:
class Article < ApplicationRecord
include ActiveModel::Validations
belongs_to :author, class_name: 'User'
has_many :taggings
has_many :tags, through: :taggings
has_many :comments
end
注释:
class Comment < ApplicationRecord
belongs_to :author, class_name: 'User'
belongs_to :article
belongs_to :parent, class_name: 'Comment', optional: true
has_many :children, class_name: 'Comment', foreign_key: 'parent_id', dependent: :delete_all
acts_as_tree order: 'created_at ASC'
end
标签:
class Tag < ApplicationRecord
has_many :taggings
has_many :articles, through: :taggings
end
标记:
class Tagging < ApplicationRecord
belongs_to :tag
belongs_to :article
end
答案 0 :(得分:2)
这是预期的行为。您有几个选择:
1)您可以创建一个服务对象,通过查询手动完成所有删除操作,从您最远的关系开始。例如:
user = User.find(id_of_user_to_destroy)
user.articles.each do |article|
article = Article.find(id_of_article_to_destroy)
Tag.where(articles: [article]).delete_all #delete_all skips callbacks
Tagging.where(article: article).delete_all
Comment.where(...).delete_all
article.destroy
end
user.destroy
这通常表现更好,但难以维持。
2)以某种方式将用户标记为“已删除”(布尔字段),然后在后台作业中调用User.destroy
。您仍将拥有大量的数据库查询,但使用本机AR dependency
属性进行维护会更容易。