如何为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
相关产品推荐
相关产品推荐

