首页 > 解决方案 > 在 Rails 中查找非孤立记录

问题描述

跟进问题:想要在 Rails 中查找没有关联记录的记录

我想知道如何将所有非孤儿记录作为 AssociationRelation 而不是数组返回。当试图从rails 6 .missing 中减去表的总记录时,结果是正确的,但它是数组的形式。

这是一个控制台示例:

p = ProductResearch.first
(Product.all - p.products.where.missing(:keywords)).class
=> Array

我如何获得关联?

(在下面@max 的帮助下,我找到了一个查询,没有遗漏,它将预期结果作为关联返回。就像:

irb(main):206:0> p.products.includes(:keywords).where.not(keywords: { id: nil }).class
=> Product::ActiveRecord_AssociationRelation

它只返回非孤儿。

标签: ruby-on-rails

解决方案


鉴于:

class Post < ApplicationRecord
  has_many :comments
end
class Comment < ApplicationRecord
  belongs_to :post
end
class CreateComments < ActiveRecord::Migration[6.0]
  def change
    create_table :comments do |t|
      # Referential integrity is for wusses! YOLO!
      t.belongs_to :post, null: true, foreign_key: false
      t.timestamps
    end
  end
end
p1 = Post.create!(title: 'Foo')
3.times { p1.comments.create! }
p2 = Post.create!(title: 'Bar')
3.times { p2.comments.create! }
p2.destroy! # orphans the comments

如果您在帖子上执行 INNER JOIN,您将只能在连接表中获得至少有一个匹配项的行:

irb(main):014:0> Comment.joins(:post)
  Comment Load (0.3ms)  SELECT "comments".* FROM "comments" INNER JOIN "posts" ON "posts"."id" = "comments"."post_id" LIMIT ?  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Comment id: 1, post_id: 1, created_at: "2021-05-11 08:59:04", updated_at: "2021-05-11 08:59:04">, #<Comment id: 2, post_id: 1, created_at: "2021-05-11 08:59:04", updated_at: "2021-05-11 08:59:04">, #<Comment id: 3, post_id: 1, created_at: "2021-05-11 08:59:04", updated_at: "2021-05-11 08:59:04">]>

这为您提供了“非孤立”帖子。

相反的当然是 OUTER JOIN:

irb(main):016:0> Comment.left_joins(:post).where(posts: { id: nil })
  Comment Load (0.3ms)  SELECT "comments".* FROM "comments" LEFT OUTER JOIN "posts" ON "posts"."id" = "comments"."post_id" WHERE "posts"."id" IS NULL LIMIT ?  [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Comment id: 4, post_id: 2, created_at: "2021-05-11 08:59:26", updated_at: "2021-05-11 08:59:26">, #<Comment id: 5, post_id: 2, created_at: "2021-05-11 08:59:26", updated_at: "2021-05-11 08:59:26">, #<Comment id: 6, post_id: 2, created_at: "2021-05-11 08:59:26", updated_at: "2021-05-11 08:59:26">]>

Rails 6.1 添加了.missing查询方法,它是上述查询的快捷方式:

Comment.where.missing(:post)

推荐阅读