考虑一个简单的关联..。
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-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 })https://stackoverflow.com/questions/5319400
复制相似问题