You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Rails的Product模型所有ActiveRecord查询默认添加deleted=0条件并可临时覆盖?

实现Product模型默认过滤已删除记录 + 临时查询已删项

当然可以实现!这是Rails里非常常见的软删除需求,我给你一步步拆解解决方案:

1. 给Product添加默认查询范围(default_scope)

首先在你的Product模型里添加默认scope,让所有常规查询自动带上deleted = 0的条件:

class Product < ActiveRecord::Base
  # 全局默认过滤已删除的记录
  default_scope { where(deleted: 0) }

  # 这里放你的其他关联、验证、方法等
  # 比如 has_many :orders
end

这样一来:

  • Product.all、Product.where(name: 'xxx')、Product.includes(:orders)这些常规查询都会自动排除deleted=1的记录
  • 其他模型的关联(比如Category.has_many :products)查询时,也会自动应用这个过滤条件,返回的都是未删除的产品

2. 添加临时查询已删除记录的方法

默认scope是全局生效的,所以我们需要添加几个类方法,用来临时跳过这个过滤:

class Product < ActiveRecord::Base
  default_scope { where(deleted: 0) }

  # 查询所有记录(包括已删除的)
  def self.with_deleted
    unscoped
  end

  # 只查询已删除的记录
  def self.only_deleted
    unscoped.where(deleted: 1)
  end

  # 可选:给单个实例添加恢复方法
  def restore
    update(deleted: 0)
  end
end

使用示例:

  • 要查询所有产品(含已删):Product.with_deleted.all
  • 只查询已删除的产品:Product.only_deleted.where(created_at: 1.week.ago..)
  • 关联查询时也能用:@category.products.with_deleted(获取该分类下所有产品,包括已删的)

3. 一些额外的小提示

  • unscoped方法会移除所有默认scope,如果你后续给Product加了其他默认scope,要注意是否需要调整(比如用except(:default_scope)来只移除特定的,但这里只针对deleted的话,unscoped完全够用)
  • 建议把删除操作改成软删除,而不是真的删除记录:可以给模型加个soft_delete方法:
    def soft_delete
      update(deleted: 1)
    end
    
    之后调用@product.soft_delete就会标记为已删除,而不是执行destroy删除数据库记录
  • 如果有需要,还可以给关联添加默认scope,比如在Category里:has_many :products, -> { where(deleted: 0) },不过因为Product已经有全局默认scope,这一步其实可以省略

内容的提问来源于stack exchange,提问作者Max Hudson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:08:32