带关联的软删除

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 不会触发更新实体的任何验证或回调。