【问题标题】:How do I get only some of the belongs_to model of a has_many relationship?如何仅获得 has_many 关系的一些 belongs_to 模型?
【发布时间】:2016-08-16 13:57:31
【问题描述】:
class Comment < ActiveRecord::Base
  has_many :replies
end

class Reply < ActiveRecord::Base
  belongs_to :comment
end

我需要获取只有特定用户回复的 cmets。

我的评论模型中有这个:

scope :with_replies_by_users, ->(*user_ids) {
joins(:replies).where(replies: { user_id: user_ids })
}


@comments = Comment.with_replies_by_users([1,2])

我认为这将返回所有回复 1 或 2 的 cmets。但它会返回这些 cmets 的所有回复。我只需要来自 1 或 2 的回复。

【问题讨论】:

  • 我相信 splat 运算符 星号 正在创建一个多维数组。尝试从您的 with_replies_by_users 范围中删除它
  • @GregAnswer - 我尝试了两种方法,我得到了相同的结果。

标签: ruby-on-rails activerecord scope


【解决方案1】:

您的范围示例仍然得到所有用户的所有回复的原因是因为这些条件用于查询 cmets。换句话说,它只用于确定从数据库中获取哪些 cmets。

例如,下面是使用范围运行的 SQL:

>> comments = Comment.joins(:replies).where(replies: { user_id: [2, 3] })
Comment Load (0.3ms)  SELECT "comments".* FROM "comments" INNER JOIN "replies" ON "replies"."comment_id" = "comments"."id" WHERE "replies"."user_id" IN (2, 3)

这只是说“根据与回复表的内部连接的结果选择 cmets”。回复的结果现在几乎毫无意义,因为只要您访问任何一个 cmets 上的回复属性:

>> comments.first.replies
Reply Load (0.2ms)  SELECT "replies".* FROM "replies" WHERE "replies"."comment_id" = ?  [["comment_id", 1]]

ActiveRecord 将在回复表中进行单独查找,因为它不考虑 cmets 查找的范围。

解决方案

在我看来,您似乎更关心回复而不是 cmets。因此,我处理此查询的一种方法是查询回复表,但需要预先加载:

>> replies = Reply.includes(:comment).where(user_id: [2, 3])
Reply Load (0.4ms)  SELECT "replies".* FROM "replies" WHERE "replies"."user_id" IN (2, 3)
Comment Load (0.2ms)  SELECT "comments".* FROM "comments" WHERE "comments"."id" = 1

最后,您只有特定用户 ID 的回复。由于急切加载,您也已经以这种方式拥有 cmets。例如,执行以下操作不会导致任何额外的提取,因为这些 cmets 在内存中。

>> replies.map(&:comment)

但请注意不要再次访问其中一个评论模型上的回复属性,否则 ActiveRecord 将执行另一次获取:

>> replies.map(&:comment).first.replies
Reply Load (0.2ms)  SELECT "replies".* FROM "replies" WHERE "replies"."comment_id" = ?  [["comment_id", 1]]

如果您仍想将其设为范围,则现在将其放入回复模型中:

scope :from_users, -> (*user_ids) do
  includes(:comment).where(user_id: user_ids)
end

然后调用:

>> Reply.from_users [2, 3]
Reply Load (0.1ms)  SELECT "replies".* FROM "replies" WHERE "replies"."user_id" IN (2, 3)
Comment Load (0.1ms)  SELECT "comments".* FROM "comments" WHERE "comments"."id" = 1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多