【问题标题】:Soft delete with associations带关联的软删除
【发布时间】:2016-07-06 12:41:21
【问题描述】:

我有三个模型:

用户:

class User < ActiveRecord::Base
  has_many :posts, :dependent => :destroy
  scope :active, -> { where(deleted: false) }
end

发帖:

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

如果没有,上述实现需要更多时间。帖子和 cmets 的数量很高,它还会产生 N+1 查询问题..

同上我已经为Post实现了destroy方法,我不知道如何高效..

我不想使用任何宝石。

请告诉我一种更好的方法来对这些关联进行软删除..

【问题讨论】:

  • 你真的需要删除帖子吗?您可以通过在检索它们时包含用户模型来替代它们。确实没有必要将所有后代标记为已删除。
  • 更好的方法是为此使用 gem:Paranoia (github.com/rubysherpas/paranoia) 或 ActsAsParanoid (github.com/ActsAsParanoid/acts_as_paranoid)。
  • @gen 发帖人说他不想使用 gem。
  • @Matt:是的,但我仍然建议使用 gem。 :) 代码和维护越少越好。

标签: ruby-on-rails soft-delete


【解决方案1】:

你真的需要删除帖子吗?您可以通过在检索它们时包含用户模型来替代它们。当可以很容易地从父级推断出所有后代时,实际上没有必要将所有后代标记为已删除。

用户:

class User < ActiveRecord::Base
  has_many :posts, :dependent => :destroy
  scope :active, -> { where(deleted: false) }
end

帖子:

class Post < ActiveRecord::Base
  belongs_to :user
  has_many :comments, :dependent => :destroy

  scope :active, -> { joins(:user).merge(User.active) }
end

【讨论】:

    【解决方案2】:

    如果一切都与效率有关(删除 N+1),我会执行以下操作。我也支持“胖模型和瘦控制器”,所以我会将你的逻辑从控制器转移到用户模型:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-13
      • 2010-10-05
      • 2015-07-10
      • 2019-08-07
      • 1970-01-01
      • 1970-01-01
      • 2013-06-19
      • 2015-10-06
      相关资源
      最近更新 更多