2012-09-20 15 views
30

यह एक साधारण सवाल हो सकता है, लेकिन मैं यहां एक सुरुचिपूर्ण समाधान खोजने के लिए अपने बालों को खींच रहा हूं। मैं उन दोनों के बीच एक has_one और belongs_to संघ के साथ दो ActiveRecord मॉडल श्रेणियां होती हैं,:पूछताछ में शून्य है_ऑन एसोसिएशन जहां क्वेरी

class Item < ActiveRecord::Base 
    has_one :purchase 
end 

class Purchase < ActiveRecord::Base 
    belongs_to :item 
end 

मैं सभी आइटम वस्तुओं को खोजने के लिए एक सुंदर तरीका के लिए देख रहा हूँ, है कि उन लोगों के साथ जुड़ा हुआ कोई खरीद वस्तु, आदर्श का सहारा के बिना एक बूलियन is_purchased या आइटम पर समान विशेषता है।

अभी मेरे पास है:

purchases = Purchase.all 
Item.where('id not in (?)', purchases.map(&:item_id)) 

कौन सा काम करता है, लेकिन मेरे लिए अक्षम लगता है, के रूप में यह दो प्रश्नों प्रदर्शन कर रहा है (और खरीद एक बड़े पैमाने पर रिकॉर्ड सेट किया जा सकता है)।

रनिंग रेल 3.1.0

उत्तर

33

यह आम बात कार्य है, एसक्यूएल बाहरी आमतौर पर इसके लिए ठीक काम करता है में शामिल हों। उदाहरण के लिए, here देखें।

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

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

तकनीकी तौर पर पहला उदाहरण 'संदर्भ' खंड के बिना काम करता है लेकिन 4 spits रेल:

आप मामले में

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

वह लिंक सही है! जॉइन काफी सटीक है जो मुझे चाहिए था, मुझे बस कहां से "जहां (" buy.item_id IS null ") के साथ प्रतिस्थापन करना था और यह जाना अच्छा है। धन्यवाद! –

+0

यदि 'has_many' या 'has_one' का उपयोग कर आप' item.join (: खरीद) ' –

21

मिले दो अन्य railsey इस करने के तरीके की तरह कुछ का उपयोग करने का प्रयास करें इसके बिना बहिष्करण चेतावनी। @dimuch समाधान के

+0

का उपयोग करके वास्तविक क्वेरी लिखने के बिना शामिल हो सकते हैं, जबकि यह स्वीकृत उत्तर से अधिक संक्षिप्त है, तो यह सभी डेटा लोड करेगा संबंधित तालिका से। यदि आप अपनी एसक्यूएल क्वेरी को अच्छी और साफ रखना चाहते हैं, तो उस कस्टम से जुड़ें जिसका उपयोग @dimuch ने सुझाया है। – deadwards

+0

@deadwards मुझे नहीं लगता कि यह सच है। 'Asset.includes (: संलग्नक)। कहीं (अनुलग्नक: {id: nil}) 'उत्पादन:' चयन करें" संपत्ति "।" Property_id "AS t0_r0, ..." अनुलग्नक "।" अपडेट_एट "AS" t1_r7 "संपत्तियों से" "संलग्नक" पर "संलग्नक" जुड़ें "संलग्नक"। "Property_id" = "संपत्ति"। "Property_id" कहां "अनुलग्नक"। "आईडी" IS NULL' है, जैसा कि @ dimuch के उदाहरण के समान है। – bronson

+0

रेल 4 रास्ता: 'Item.includes (: खरीद)। संदर्भ (: खरीद)। कहीं (खरीद: {id: nil})'। यदि आप उस पर to_sql को कॉल करते हैं, तो आप देखेंगे कि यह निश्चित रूप से सभी डेटा लोड नहीं करता है। यह स्वीकार्य उत्तर के समान ही वही काम करता है। – bronson

3

एक अधिक संक्षिप्त संस्करण left_outer_joins विधि रेल 5 में पेश उपयोग करने के लिए है:

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

ध्यान दें कि left_outer_joins कॉल में :purchase विलक्षण है (यह द्वारा बनाई गई विधि का नाम है has_one घोषणा), और where खंड :purchases बहुवचन है (यहां यह तालिका का नाम है जो id फ़ील्ड से संबंधित है।)

+1

क्या आप रेल संस्करण निर्दिष्ट कर सकते हैं? मेरा मानना ​​है कि यह है> 5. – niborg

+0

धन्यवाद @ निबोर्ग। वह एक अच्छा विचार है। – ReggieB

संबंधित मुद्दे