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

Rails中将Newsletter::Author的复杂SQL查询改写为Arel或ActiveRecord

改造后的ActiveRecord实现

你可以直接将原scope替换为以下代码,逻辑和原原生SQL完全对齐,且返回ActiveRecord::Relation支持后续链式调用其他查询方法:

# app/models/newsletter/author.rb
scope :without_submissions_for, lambda { |newsletter_id|
  # 子查询:筛选出有草稿、无提交内容的成员ID
  eligible_member_ids = GroupMember
    .joins(:stories)
    .where(newsletter_stories: { status: :draft })
    .where.not(
      exists: Newsletter::Story
                .where(status: :submitted)
                .where("newsletter_stories.author_id = group_members.id")
    )
    .distinct
    .select(:id)

  # 主查询:匹配对应Newsletter下未删除、符合成员条件的作者
  where(discarded_at: nil)
    .where(newsletter_id: newsletter_id)
    .where(group_member_id: eligible_member_ids)
}

纯Arel无手写SQL版本

如果你需要完全避免手写SQL片段,可以用Arel表构建查询条件,写法如下:

# app/models/newsletter/author.rb
scope :without_submissions_for, lambda { |newsletter_id|
  group_members = GroupMember.arel_table
  stories = Newsletter::Story.arel_table

  # 构造「存在提交状态稿件」的Arel条件
  has_submitted_story = stories
    .project(1)
    .where(stories[:author_id].eq(group_members[:id]))
    .where(stories[:status].eq(Newsletter::Story.statuses[:submitted]))
    .exists

  eligible_member_ids = GroupMember
    .joins(:stories)
    .where(newsletter_stories: { status: :draft })
    .where.not(has_submitted_story)
    .distinct
    .select(:id)

  where(discarded_at: nil)
    .where(newsletter_id: newsletter_id)
    .where(group_member_id: eligible_member_ids)
}

两种写法生成的SQL和你原实现的执行效率完全一致,且符合Rails ActiveRecord查询的通用规范,方便后续维护。

内容的提问来源于stack exchange,提问作者Michael Bester

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 13:39:04