2012-09-20 24 views
30

nil has_one derneklerini bulmak Bu basit bir soru olabilir, ancak burada zarif bir çözüm bulmak için benim saçımı çekiyor gibi görünüyor. ideal başvurmadan,Sorgu nerede

class Item < ActiveRecord::Base 
    has_one :purchase 
end 

class Purchase < ActiveRecord::Base 
    belongs_to :item 
end 

Bütün Öğe nesneleri bulmak için zarif bir yol arıyorum, bunlarla ilişkili hiçbir alım nesne var: Aralarında bir has_one ve belongs_to dernek ile, iki ActiveRecord modeli sınıfları Boole is_purchased veya Öğeye benzer bir özniteliğe sahip olmak.

Şu anda var:

o iki sorgu performans gösteriyorsa (ve alımları büyük bir kayıt kümesi olabilir) gibi çalışır, ama bana verimsiz görünmektedir
purchases = Purchase.all 
Item.where('id not in (?)', purchases.map(&:item_id)) 

.

Koşu Raylar 3.1.0

cevap

33

Oldukça yaygın bir görev, SQL DIŞ genellikle bunun için çalışıyor JOIN. Örneğin, bir here göz atın. İlk örnek 'referanslar' koşulu olmadan çalışır ancak

Item.includes(:purchase).references(:purchase).where("purchases.id IS NULL") 

Item.includes(:purchase).where(purchases: { id: nil }) 

Teknik olarak 4 tükürür Raylar: Eğer durumda

Bunu yapmanın

not_purchased_items = Item.joins("LEFT OUTER JOIN purchases ON purchases.item_id = items.id").where("purchases.id IS null") 
+1

Bu bağlantı mükemmel! Birleşime ihtiyacım olan şey tam olarak buydu, sadece yukarıdaki yeri ("purchases.item_id IS null") ile değiştirmek zorunda kaldım ve gitmesi güzel. Teşekkürler! –

+0

Eğer 'has_many' veya' has_one' kullanılıyorsa, 'Item.join (: alımları) ' –

21

Bulunan diğer iki railsey yolları gibi bir şey kullanmayı deneyin kullanımdan kaldırılma uyarıları. @dimuch çözeltisi

+0

kullanarak gerçek sorguyu yazmak zorunda kalmadan birleştirmeyi yapabilirsiniz. Bu, kabul edilen yanıttan daha kısa olsa da, tüm verileri yükleyecektir. ilişkili tablodan. SQL sorgunuzu güzel ve düzenli tutmak istiyorsanız, bunun yerine @dimuch'un önerdiği özel birleştirme kullanın. – deadwards

+0

@Deadwards Bunun doğru olduğunu düşünmüyorum. Asset.includes (: attachments) .where (ekleri: {id: nil}) 'üretir:' SELECT "asset". "Property_id" AS t0_r0, ... "attachments". "Updated_at" AS t1_r7 FROM "varlıklar" LEFT OUTER JOIN "attachments" ON "attachments". "Property_id" = "assets". "Property_id" WHERE "attachments". "Id" IS NULL ", @ dimuch'un örneğiyle aynı. – bronson

+0

Raylar 4 yollu: 'Item.includes (: alımlar) .references (: alımları) .where (alımlar: {id: nil})'. Üzerinde to_sql çağırırsanız, kesinlikle tüm verileri yüklemediğini görürsünüz. Tam olarak kabul edilen cevapla aynı şeyi yapar. – bronson

3

daha kısa sürüm raylar 5 tanıtılan left_outer_joins yöntemini kullanmaktır: left_outer_joins çağrısında :purchase tekil olduğu

Item.left_outer_joins(:purchase).where(purchases: {id: nil}) 

Not (bu tarafından oluşturulan yöntem adıdır has_one bildirimi) ve where maddesinde :purchases çoğul (burada id alanının ait olduğu tablonun adıdır.)

+1

Rails sürümünü belirtebilir misiniz? Bence bu,> 5. – niborg

+0

teşekkürler @niborg. Bu iyi bir fikir. – ReggieB