You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Ruby on Rails中如何编写两类Audit对应的named scope?

嘿,针对你在Ruby on Rails里使用Audit gem的两个需求,我整理了对应的named scope写法,你可以直接放到Audit模型里用:

1. 获取无关联Auditable的Audit记录

这个scope会覆盖两种情况:要么Audit从未关联过任何Auditable模型,要么曾经关联的Auditable已经被删除了。

class Audit < ApplicationRecord
  belongs_to :auditable, polymorphic: true, optional: true

  scope :without_auditable, -> {
    # 匹配本身就没有关联的记录
    where(auditable_id: nil)
      .or(
        # 匹配关联的Auditable已被删除的记录
        where.not(auditable_type: nil).where.not(
          exists(
            Arel::Table.new(auditable_type.tableize).unscoped.where(
              id: arel_table[:auditable_id]
            )
          )
        )
      )
  }

如果你的Auditable类型不多,也可以用更直观的left join版本:

scope :without_auditable, -> {
  left_joins(:auditable)
    .where(auditable: { id: nil })
}

解释:第一种写法用exists子查询,能适配所有类型的Auditable模型;第二种left join方式更易读,Rails会自动处理多态关联的join逻辑,同样能得到正确结果。

2. 获取关联Order未被删除的Audit记录

这个scope专门筛选那些关联的Order仍然存在(没被删除)的Audit记录:

scope :with_existing_order, -> {
  where(auditable_type: "Order")
    .where(
      exists(
        Order.unscoped.where(
          id: arel_table[:auditable_id],
          deleted_at: nil # 用软删除(比如paranoia)就保留这行,硬删除则删掉
        )
      )
    )
}

解释:

  • 先通过auditable_type: "Order"锁定所有关联Order的Audit;
  • exists子查询确保对应的Order记录存在,unscoped是为了绕过Order模型上的默认scope,避免过滤掉有效记录;
  • 要是用的是硬删除(直接destroy,无deleted_at字段),去掉deleted_at: nil这一行即可。

内容的提问来源于stack exchange,提问作者Umesh Malhotra

火山引擎 最新活动