考虑一个简单的关联..。
class Person
has_many :friends
end
class Friend
belongs_to :person
end
要让所有在ARel和/或meta_where上没有朋友的人都加入进来,最干净的方法是什么?
那么has_many :直通版本呢?
class Person
has_many :contacts
has_many :friends, :through => :contacts, :uniq => true
end
class Friend
has_many :contacts
has_many :people, :through => :contacts, :uniq => true
end
class Contact
belongs_to :friend
belongs_to :person
end
我真的不想使用counter_cache --从我读到的内容来看,它不适用于has_many:
我不想提取所有的person.friends记录,然后在Ruby语言中遍历它们--我希望有一个可以在meta_search gem中使用的查询/范围
我不关心查询的性能成本
离实际的SQL越远越好。
发布于 2011-03-16 08:33:30
这仍然非常接近SQL,但在第一种情况下,它应该会让没有朋友的每个人:
Person.where('id NOT IN (SELECT DISTINCT(person_id) FROM friends)')
发布于 2011-04-07 01:05:11
更新4- Rails 6.1
感谢Tim Park指出,在即将到来的6.1中,您可以这样做:
Person.where.missing(:contacts)
多亏了他链接到的the post。
更新3- Rails 5
感谢@Anson出色的Rails 5解决方案(下面给他一些+1的答案),你可以使用left_outer_joins
来避免加载关联:
Person.left_outer_joins(:contacts).where(contacts: { id: nil })
我在这里包含了它,这样人们就会找到它,但他应该为此得到+1。很棒的新增功能!
更新2
有人问到了相反的问题,没有人的朋友。正如我在下面评论的那样,这实际上让我意识到最后一个字段(上面::person_id
)实际上不必与您返回的模型相关,它只需要是连接表中的一个字段。它们都将是nil
,所以可以是其中的任何一个。这为上述问题提供了更简单的解决方案:
Person.includes(:contacts).where(contacts: { id: nil })
然后切换到返回没有人的朋友变得更加简单,您只需更改前面的类:
Friend.includes(:contacts).where(contacts: { id: nil })
更新
在评论中有一个关于has_one
的问题,所以只需要更新。这里的诀窍是,includes()
需要关联的名称,而where
需要的是表的名称。对于has_one
,关联通常以单数形式表示,因此会发生变化,但where()
部分保持不变。因此,如果仅使用Person
has_one :contact
,则语句将为:
Person.includes(:contact).where(contacts: { person_id: nil })
原创
更好的:
Person.includes(:friends).where(friends: { person_id: nil })
对于hmt来说,这基本上是一样的,你依赖于一个没有朋友的人也将没有联系人的事实:
Person.includes(:contacts).where(contacts: { person_id: nil })
发布于 2013-09-30 00:05:09
没有朋友的人
Person.includes(:friends).where("friends.person_id IS NULL")
或者至少有一个朋友
Person.includes(:friends).where("friends.person_id IS NOT NULL")
您可以通过在Friend
上设置作用域来使用Arel完成此操作
class Friend
belongs_to :person
scope :to_somebody, ->{ where arel_table[:person_id].not_eq(nil) }
scope :to_nobody, ->{ where arel_table[:person_id].eq(nil) }
end
然后,至少有一个朋友的人:
Person.includes(:friends).merge(Friend.to_somebody)
没有朋友的人:
Person.includes(:friends).merge(Friend.to_nobody)
https://stackoverflow.com/questions/5319400
复制相似问题