【问题标题】:Is there a way to check for empty arrays returned from ActiveRecord queries?有没有办法检查从 ActiveRecord 查询返回的空数组?
【发布时间】:2026-02-12 07:15:02
【问题描述】:

我想编写一个行为如下的 activerecord 查询:

User.joins(:comment).where(comments: {replies: []})

返回没有回复的用户。

User.first.comment.first.replies => [] returns an empty array

我只需要它是一个 activerecord 关系,所以使用 ruby​​ 代码是行不通的。有没有办法使用 activerecord 检查空数组?

编辑: 示例架构

create_table "users", force: :cascade do |t|
t.string "email",
t.string "password"
end

create_table "comments" do |t|
t.string "content"
end

create_table "replies" do |t|
t.string "content"
end

用户.rb

class User < ActiveRecord::Base
has_many :comments
end

评论.rb

class Comment < ActiveRecord::Base
belongs_to :user
has_many :replies
end

回复.rb

class Reply < ActiveRecord::Base
belongs_to :comment
belongs_to :user
end

这些只是示例模型,但这应该说明与这些相关的模型的问题。

如果一个用户(id 为 1)做了 3 个 cmets,而这 3 个 cmets 中只有 1 个有回复,我如何让其他 2 个 cmets 处于 activerecord 关系中?

【问题讨论】:

  • 能否请您发布 cmets 表的架构?
  • 我使用的模型只是示例,但如果有帮助,我可以使用这些模型创建示例架构。
  • 我最想了解回复列以及它是如何存储的(/如果我理解错了,它是另一个表)。我可以给你一个 hacky 的例子,说明如何暂时让它工作,但为了获得最佳方法,我需要更多关于数据如何存储的信息。编辑:也可以很好地获取模型结构以及表的关联方式。
  • 好的,给我几分钟,我会在
  • commentreplies之间是否定义了ActiveRecord::Relation,即Comment模型中的has_many :replies?或者repliescomments 上的一个列,它存储为数组/JSON?

标签: ruby-on-rails ruby activerecord


【解决方案1】:

使用 counter_cache 可以让设计更简单

在回复中添加 counter_cache

class Reply < ActiveRecord::Base
belongs_to :comment, counter_cache: true
belongs_to :user
end

在评论表中添加计数器列

create_table "comments" do |t|
t.string "content"
t.integer "replies_count"
end

replies_count 的简单使用条件

User.joins(:comment).where(comments: {replies_count: 0})

更多信息请参考rails doc

【讨论】:

    【解决方案2】:

    您需要使用从commentsrepliesLEFT JOIN,这将返回所有cmets,无论是否对每条评论都有回复。通常在 rails 中加入,即当你执行 @comment.repliesUser.joins(comments: :replies) 时执行的加入是 INNER JOINActiveRecord 没有用于编写左连接查询的漂亮 DSL,但确实允许它们以下列方式:

    # Find all users who have at least one comment with no replies
    User.joins(:comments)
      .joins("LEFT JOIN replies ON replies.comment_id = comments.id")
      .where("replies.id IS NULL")
    
    # Find all comments for a user that don't have replies
    @user.comments
      .joins("LEFT JOIN replies ON replies.comment_id = comments.id")
      .where("replies.id IS NULL")
    

    我包含了两个 sn-ps,因为在您的问题中,不清楚您是想为某个没有回复的用户查找用户还是 cmets。

    where("replies.id IS NULL") 是一个过滤器,它查找LEFT JOIN 中没有匹配回复的所有评论,并提供您想要的结果。这是一个非常常见的 SQL 技巧,值得牢记以备将来挖掘数据。

    【讨论】: