带关联的软删除
Soft delete with associations
我有三个模型:
用户:
class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
scope :active, -> { where(deleted: false) }
end
Post:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments, :dependent => :destroy
scope :active, -> { where(deleted: false) }
end
评论:
class Comment < ActiveRecord::Base
belongs_to :post
scope :active, -> { where(deleted: false) }
end
现在,我正在为 User
执行软删除,并且我在所有三个表中都有名为 deleted
的列 (User, Post, Comment
)
用户销毁方法:
def destroy
@user = user.find(params[:id])
if @user.update_attributes(deleted: true)
@user.posts.each do |post|
post.comments.update_all(deleted: true)
end
@user.posts.update_all(deleted: true)
end
end
如果没有,上面的实现会花费更多的时间。帖子和评论的数量很高,这也造成了 N+1 查询问题..
和上面一样我已经为Post
实现了destroy
方法,我不知道如何有效地做..
我不想使用任何类型的gem。
请告诉我一种更好的方法来对这类关联进行软删除..
你真的需要删除帖子吗?您可以通过在检索它们时包含用户模型来确定它们的范围。将所有后代标记为已删除确实没有必要,因为它可以很容易地从父级推断出来。
用户:
class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
scope :active, -> { where(deleted: false) }
end
Post:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments, :dependent => :destroy
scope :active, -> { joins(:user).merge(User.active) }
end
如果一切都与效率有关(删除 N+1),我会执行以下操作。我也支持 "fat-models and skinny-controllers",所以我会将您的逻辑从控制器移至用户模型:
class User < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_many :comments, through: :posts
scope :active, -> { where(deleted: false) }
after_save :delete_posts_and_comments, if: :delete_posts?
private
def delete_posts?
deleted_changed? && deleted
end
def delete_posts_and_comments
posts.update_all(deleted: true)
comments.update_all(deleted: true)
end
end
当然,您可以使用相同的模式来撤消删除。
注意! update_all 不会触发更新实体的任何验证或回调。
我有三个模型:
用户:
class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
scope :active, -> { where(deleted: false) }
end
Post:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments, :dependent => :destroy
scope :active, -> { where(deleted: false) }
end
评论:
class Comment < ActiveRecord::Base
belongs_to :post
scope :active, -> { where(deleted: false) }
end
现在,我正在为 User
执行软删除,并且我在所有三个表中都有名为 deleted
的列 (User, Post, Comment
)
用户销毁方法:
def destroy
@user = user.find(params[:id])
if @user.update_attributes(deleted: true)
@user.posts.each do |post|
post.comments.update_all(deleted: true)
end
@user.posts.update_all(deleted: true)
end
end
如果没有,上面的实现会花费更多的时间。帖子和评论的数量很高,这也造成了 N+1 查询问题..
和上面一样我已经为Post
实现了destroy
方法,我不知道如何有效地做..
我不想使用任何类型的gem。
请告诉我一种更好的方法来对这类关联进行软删除..
你真的需要删除帖子吗?您可以通过在检索它们时包含用户模型来确定它们的范围。将所有后代标记为已删除确实没有必要,因为它可以很容易地从父级推断出来。
用户:
class User < ActiveRecord::Base
has_many :posts, :dependent => :destroy
scope :active, -> { where(deleted: false) }
end
Post:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments, :dependent => :destroy
scope :active, -> { joins(:user).merge(User.active) }
end
如果一切都与效率有关(删除 N+1),我会执行以下操作。我也支持 "fat-models and skinny-controllers",所以我会将您的逻辑从控制器移至用户模型:
class User < ActiveRecord::Base
has_many :posts, dependent: :destroy
has_many :comments, through: :posts
scope :active, -> { where(deleted: false) }
after_save :delete_posts_and_comments, if: :delete_posts?
private
def delete_posts?
deleted_changed? && deleted
end
def delete_posts_and_comments
posts.update_all(deleted: true)
comments.update_all(deleted: true)
end
end
当然,您可以使用相同的模式来撤消删除。
注意! update_all 不会触发更新实体的任何验证或回调。