खाली ActiveRecord संबंध वापस कैसे करें?


246

अगर मेरे पास एक लंबो के साथ गुंजाइश है और यह एक तर्क लेता है, तो तर्क के मूल्य के आधार पर, मुझे पता चल सकता है कि कोई भी मैच नहीं होगा, लेकिन मैं अभी भी एक रिलेशन को वापस करना चाहता हूं, खाली सरणी को नहीं:

scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }

जो मैं वास्तव में चाहता हूं वह एक "कोई नहीं" विधि है, "सभी" के विपरीत, यह एक ऐसा संबंध देता है जो अभी भी जंजीर हो सकता है, लेकिन इसके परिणामस्वरूप क्वेरी शार्ट-सर्किट हो जाती है।


यदि आप केवल क्वेरी करते हैं, तो इसे चलाएं एक संबंध वापस आ जाएगा: User.where ('id in (?)', [])। Class => ActiveRecord :: Relation। क्या आप क्वेरी से पूरी तरह बचने की कोशिश कर रहे हैं?
ब्रायन डिटर्जिंग

1
सही बात। अगर मुझे पता है कि संभवतः कोई मैच नहीं हो सकता है, तो आदर्श रूप से, क्वेरी को पूरी तरह से टाला जा सकता है। मैंने इसे केवल ActiveRecord :: Base: "def self.none में जोड़ा है; जहाँ: (id => 0); अंत" मुझे जो चाहिए उसके लिए ठीक काम करने लगता है।
dajajic

1
> क्या आप क्वेरी से पूरी तरह बचने की कोशिश कर रहे हैं? पूरी तरह से समझ में आता है, लंगड़ा की तरह हमें उसके लिए DB को हिट करने की आवश्यकता है
dolzenko

जवाबों:


478

रेल 4 में अब एक "सही" तंत्र है:

>> Model.none 
=> #<ActiveRecord::Relation []>

14
अब तक इसे वापस 3.2 या उससे पहले पोर्ट नहीं किया गया है। केवल बढ़त (4.0)
क्रिस ब्लूम


2
बस रेल 4.0.5 के साथ कोशिश की और यह काम कर रहा है। इस सुविधा ने इसे रेल 4.0 रिलीज के लिए बनाया।
विकसित करें

3
@AugustinRiedinger Model.scopedवह करता है जो आप रेल की तलाश में हैं 3.
टिम डिगिन्स

9
रेल 4.0.5 के रूप में, Model.noneकाम नहीं करता है। आपको अपने वास्तविक मॉडल नामों में से एक का उपयोग करने की आवश्यकता है , जैसे User.noneया क्या-क्या-आप।
ग्रांट बर्चमियर

77

एक अधिक पोर्टेबल समाधान जिसमें "आईडी" कॉलम की आवश्यकता नहीं होती है और यह नहीं मानता है कि 0 की आईडी के साथ एक पंक्ति नहीं होगी:

scope :none, where("1 = 0")

मैं अभी भी अधिक "सही" तरीके की तलाश कर रहा हूं।


3
हाँ, मैं वास्तव में हैरान हूँ कि ये उत्तर हमारे पास सबसे अच्छे हैं। मुझे लगता है कि ActiveRecord / Arel अभी भी बहुत अपरिपक्व होना चाहिए। अगर मुझे रूबी में एक खाली सरणी बनाने के लिए परिक्रमा से गुजरना होता तो मैं वास्तव में नाराज हो जाता। एक ही बात यहाँ, मूल रूप से।
बैंगनीजकेट

हालांकि कुछ हद तक hackish, इस है रेल 3.2 के लिए सही तरीका। रेल 4 के लिए, @ steveh7 का अन्य उत्तर यहां देखें: stackoverflow.com/a/10001043/307308
Scarver2

scope :none, -> { where("false") }
at१

43

रेल 4 में आ रहा है

रेल 4 में, ActiveRecord::NullRelationकॉल की तरह से एक चेनेबल लौटाया जाएगा Post.none

न तो यह, और न ही जंजीर तरीके, डेटाबेस के लिए प्रश्न उत्पन्न करेंगे।

टिप्पणियों के अनुसार:

ActiveRecord लौटाया गया :: NullRelation संबंध से विरासत में मिला है और Null Object पैटर्न को लागू करता है। यह परिभाषित अशक्त व्यवहार वाली एक वस्तु है और हमेशा डेटाबेस को क्वेर किए बिना अभिलेखों का एक खाली सरणी देता है।

स्रोत कोड देखें ।


42

आप "कोई नहीं" नामक एक गुंजाइश जोड़ सकते हैं:

scope :none, where(:id => nil).where("id IS NOT ?", nil)

यह आपको एक खाली ActiveRecord :: Relation देगा

आप इसे ActiveRecord में भी जोड़ सकते हैं :: एक शुरुआती में आधार (यदि आप चाहें):

class ActiveRecord::Base
 def self.none
   where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil)))
 end
end

इस तरह से कुछ पाने के लिए बहुत सारे तरीके, लेकिन निश्चित रूप से एक कोड आधार में रखने के लिए सबसे अच्छी बात नहीं है। मैंने गुंजाइश का उपयोग किया है: कोई भी जब रीफैक्टरिंग और खोज नहीं कर रहा है कि मुझे खाली ActiveRecord की गारंटी देने की आवश्यकता है :: थोड़े समय के लिए संबंध।


14
where('1=2')थोड़ा और अधिक संक्षिप्त हो सकता है
Marcin Raczkowski

10
यदि आप नए 'सही' उत्तर पर नीचे नहीं जाते हैं: Model.noneतो आप यह कैसे करेंगे।
जोएसे

26
scope :none, limit(0)

एक खतरनाक समाधान है क्योंकि आपके दायरे का पीछा किया जा सकता है।

User.none.first

पहला उपयोगकर्ता लौटाएगा। यह उपयोग करने के लिए सुरक्षित है

scope :none, where('1 = 0')

2
यह सही एक 'गुंजाइश है: कोई नहीं, जहां (' 1 = 0 ')'। यदि आपके पास पेजिनेशन है तो दूसरा विफल हो जाएगा
फेडरिको

14

मुझे लगता है कि जिस तरह से यह अन्य विकल्पों के लिए लग रहा है मुझे पसंद है:

scope :none, limit(0)

इस तरह से कुछ के लिए अग्रणी:

scope :users, lambda { |ids| ids.present? ? where("user_id IN (?)", ids) : limit(0) }

मैं इसे पसंद करता हूं। मुझे यकीन नहीं है कि where(false)वह काम क्यों नहीं करेगा - यह गुंजाइश को अपरिवर्तित छोड़ देता है।
aceofspades

4
खबरदार कि limit(0)ओवरराइड हो सकता है अगर आप कॉल .firstया .lastश्रृंखला में बाद में, के बाद से रेल में संलग्न कर देगा LIMIT 1कि प्रश्न के।
zykadelic

2
@aceofspades जहां (झूठा) काम नहीं करता है (रेल 3.0) लेकिन कहां ('झूठा') करता है। ऐसा नहीं है कि आप शायद अब इसकी देखभाल करते हैं 2013 :)
रिची

धन्यवाद @ रिची, तब से मुझे लगता है कि noneजैसा कि नीचे उल्लेख किया गया है, हमारा भी संबंध है।
ऐसोफैड्स

3

स्कोप का उपयोग करें:

स्कोप: for_users, lambda {| उपयोगकर्ता | users.any? ? कहाँ ("user_id IN (?)", users.map (&: id) .join (',')): sceded}

लेकिन, आप अपना कोड भी सरल बना सकते हैं:

स्कोप: for_users, lambda {| उपयोगकर्ता | अगर (: user_id => users.map (&: id)) यदि users.any? }

यदि आप एक खाली परिणाम चाहते हैं, तो इसका उपयोग करें (यदि शर्त हटा दें):

स्कोप: for_users, lambda {| उपयोगकर्ता | कहाँ (: user_id => users.map (&: id))}

"स्कोप्ड" या नील को वापस करने से वह नहीं मिलता जो मैं चाहता हूं, जो परिणामों को शून्य तक सीमित करता है। "स्कोप्ड" या नील को वापस करने से गुंजाइश पर कोई प्रभाव नहीं पड़ता है (जो कुछ मामलों में उपयोगी है, लेकिन मेरा नहीं)। मैं अपने स्वयं के उत्तर के साथ आया (ऊपर टिप्पणियां देखें)।
dajajic

मैंने आपके लिए एक सरल समाधान जोड़ा, साथ ही साथ एक खाली परिणाम :)
Pan Thomakos


1

वेरिएंट भी हैं, लेकिन ये सभी डीबी के लिए अनुरोध कर रहे हैं

where('false')
where('null')

2
BTW ध्यान दें कि ये तार होने चाहिए। where(false)या where(nil)बस नजरअंदाज कर दिया है।
महमूफ़
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.