2011-03-16 117 views
12
class Person < ActiveRecord::Base 
    has_many :pets 

    scope :with_dog, join(:pets).where("pets.type = 'Dog'") 
    scope :without_pets ??????????????????????????????????? 
end 

class Pet < ActiveRecord::Base 
    belongs_to :people 
end 

我想將範圍添加到Person模型,該模型返回沒有寵物的人。有任何想法嗎?我覺得這很明顯,但目前它正在逃避我。查找軌中沒有關聯記錄的記錄3

回答

8

嘗試這樣:

Person.joins('left outer join pets on persons.id=pets.person_id'). 
     select('persons.*,pets.id'). 
     where('pets.id is null') 

我沒有測試它,但它應該工作。

這個想法是,我們正在執行一個左外連接,所以對於沒有寵物的每個人,寵物字段將爲空。您可能需要在連接中包含:readonly => false,因爲在join()傳遞字符串時,ActiveRecord會返回只讀對象。從修正「加入」到「聯接」的查詢方法名:如果你的寵物模式有一個人的ID,但也許這種嘗試可以幫助你以某種方式

scope :with_dog, joins(:pets).where("pets.type = 'Dog'") 
scope :without_pets, joins(:pets).where("pets.person_id != persons.id") 

更新

+0

產生的SQL失敗:SELECT *人,pets.id FROM'persons'左外連接的寵物,其中persons.id = pets.person_id WHERE'persons'。 'deleted' = 0 AND(pets.id爲空) – Shagymoe 2011-03-16 23:32:00

+0

糟糕!我打錯了那個連接。它應該是「...在persons.id = pets.person_id」,而不是「... where persons.id = ...」。 – 2011-03-16 23:55:53

+0

你需要選擇('persons。*,pets.id')中的「,pets.id」嗎?它有可能與persons.id發生衝突,除非你像這樣對列進行別名化:select('persons。*,pets.id as pet_id') – mkirk 2011-04-01 20:16:44

5

Mark Westling的回答是正確的。外連接是正確的路要走。內部聯接(如果傳遞聯合體的名稱/符號而不是您自己的SQL,則聯接方法會生成該聯接)將不起作用,因爲它不包括沒有寵物的人。

這被寫成範圍:(如果不行,請嘗試使用「人」代替「人」 - 我不知道你的表名是什麼)

scope :without_pets, joins("left outer join pets on pets.person_id = persons.id").where("pets.id is null") 

21
scope :without_pets, lambda { includes(:pets).where('pets.id' => nil) } 
+0

儘管LEFT OUTER JOIN不是'includes'的目的,它與組合的查詢將導致LEFT OUTER JOIN。 – lulalala 2012-07-09 10:17:12

+2

這可以工作,不管目的。手寫的sql比接受的答案少=我認爲它更好。 – 2012-07-22 19:59:52

1

您必須使用LEFT OUTER JOIN才能找到沒有關聯記錄的記錄。下面是我使用的代碼改編版本:

scope :without_pets, joins('LEFT OUTER JOIN pets ON people.id = pets.person_id').group('people.id').having('count(pets.id) = 0') 
相關問題