रेल मॉडल के लिए डिफ़ॉल्ट क्रम?


255

मैं अपने मॉडल में एक डिफ़ॉल्ट सॉर्ट क्रम निर्दिष्ट करना चाहूंगा।

ताकि जब मैं इसे .where()निर्दिष्ट किए बिना करूं तो .order()यह डिफ़ॉल्ट प्रकार का उपयोग करता है। लेकिन अगर मैं एक निर्दिष्ट करता हूं .order(), तो यह डिफ़ॉल्ट को ओवरराइड करता है।

जवाबों:


544

default_scope

यह रेल 4+ के लिए काम करता है:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

रेल 2.3, 3 के लिए, आपको इसके बजाय इसकी आवश्यकता है:

default_scope order('created_at DESC')

रेल के लिए 2.x:

default_scope :order => 'created_at DESC'

created_atवह क्षेत्र है जहां आप चाहते हैं कि डिफ़ॉल्ट छँटाई हो।

नोट: ASC , आरोही के लिए उपयोग करने के लिए कोड है और DESC अवरोही ( desc, नहीं) के लिए है dsc !) के लिए है।

scope

एक बार आपके द्वारा उपयोग किए जाने के बाद आप इसका उपयोग भी कर सकते हैं scope:

class Book < ActiveRecord::Base
  scope :confirmed, :conditions => { :confirmed => true }
  scope :published, :conditions => { :published => true }
end

रेल 2 के लिए आपको चाहिए named_scope

:published गुंजाइश आपको देता है Book.published के बजाय Book.find(:published => true)

3 रेल के बाद से आप उन तरीकों को एक साथ 'चेन' कर सकते हैं, उन्हें उनके बीच की अवधि के साथ समेट कर, इसलिए उपरोक्त स्कोप के साथ आप उनका उपयोग नहीं कर सकते हैं Book.published.confirmed

इस पद्धति के साथ, क्वेरी को वास्तव में निष्पादित नहीं किया जाता है जब तक कि वास्तविक परिणामों की आवश्यकता नहीं होती है (आलसी मूल्यांकन), इसलिए 7 स्कोप को एक साथ जंजीर किया जा सकता है लेकिन केवल 1 वास्तविक डेटाबेस क्वेरी के परिणामस्वरूप, प्रदर्शन समस्याओं से बचने के लिए 7 अलग-अलग प्रश्नों को निष्पादित करने से बचें।

आप एक पारित पैरामीटर का उपयोग कर सकते हैं जैसे कि एक तारीख या एक user_id (कुछ ऐसा जो रन-टाइम में बदल जाएगा और इसलिए इस तरह के 'आलसी मूल्यांकन' की आवश्यकता होगी, एक लंबोदर के साथ, इस तरह:

scope :recent_books, lambda 
  { |since_when| where("created_at >= ?", since_when) }
  # Note the `where` is making use of AREL syntax added in Rails 3.

अंत में आप के साथ डिफ़ॉल्ट गुंजाइश को अक्षम कर सकते हैं:

Book.with_exclusive_scope { find(:all) } 

या इससे भी बेहतर:

Book.unscoped.all

जो किसी भी फ़िल्टर (शर्तों) या सॉर्ट (ऑर्डर द्वारा) को अक्षम कर देगा।

ध्यान दें कि पहला संस्करण Rails2 + में काम करता है जबकि दूसरा (अनकैप्ड) Rails3 + के लिए ही है


तो ... अगर आप सोच रहे हैं, हम्म, तो ये सिर्फ तरीकों की तरह हैं ..., हाँ, यह वही है जो ये स्कोप हैं!
वे होने की तरह हैं, def self.method_name ...code... endलेकिन हमेशा माणिक के साथ वे आपके लिए चीजों को आसान बनाने के लिए छोटे वाक्यविन्यास शॉर्टकट (या 'चीनी') हैं!

वास्तव में वे कक्षा स्तर के तरीके हैं क्योंकि वे 'सभी' रिकॉर्ड के 1 सेट पर काम करते हैं।

उनका प्रारूप हालांकि बदल रहा है, रेल 4 के साथ एक कॉल करने योग्य वस्तु को पारित किए बिना # सीप का उपयोग करते समय पदावनति की चेतावनी है। उदाहरण के लिए गुंजाइश: लाल, जहां (रंग: 'लाल') को बदल दिया जाना चाहिएscope :red, -> { where(color: 'red') }

साइड नोट के रूप में, जब गलत तरीके से उपयोग किया जाता है, तो डिफ़ॉल्ट _scope का दुरुपयोग / दुरुपयोग किया जा सकता है।
यह मुख्य रूप से तब होता है जब इसका उपयोग केवल परिणामों को क्रमबद्ध करने के बजाय डिफ़ॉल्ट चयन ( डिफ़ॉल्ट के लिए एक बुरा विचारwhere ) को सीमित करने (फ़िल्टर करने) जैसी क्रियाओं के लिए किया जाता है । के लिए चयन, बस नियमित नामित स्कोप का उपयोग करें। और क्वेरी में उस स्कोप को जोड़ें, जैसे कि नामांकित स्कोप।
whereBook.all.publishedpublished

अंत में, स्कोप वास्तव में बहुत अच्छे हैं और आपको एक 'वसा मॉडल पतली नियंत्रक' DRYer दृष्टिकोण के लिए मॉडल में चीजों को पुश करने में मदद करते हैं।


1
कृपया के रूप में इस पोस्ट में वर्णित उपयोग करने से पहले default_scope उपयोग के बारे में डेव थॉमस 'चेतावनी पर विचार करें: pragdave.blogs.pragprog.com/pragdave/2012/03/...
रीटो

3
क्या ऐसा करना अधिक सुरक्षित नहीं होगा default_scope { order("#{table_name}.created_at DESC") }?
सिरिलचम्पियर

37
रेल 4:default_scope { order(created_at: :desc) }
मार्कस

2
कम से कम 4.2.6के आधार पर सॉर्ट करने लगता है updated_atनहीं created_at
ऐन तोवहरी

2
@AinTohvri सही है। इसने मुझे रेल्स 4.2 में आश्चर्यचकित कर दिया। updated_atडिफ़ॉल्ट रूप से क्यों छाँटें ? : - |
साठ ४

112

ऊपर माइकल के उत्कृष्ट उत्तर के लिए एक त्वरित अपडेट।

रेल 4.0 के लिए आपको अपने ब्लॉक को इस तरह लगाना होगा:

class Book < ActiveRecord::Base
  default_scope { order('created_at DESC') }
end

ध्यान दें कि आदेश विवरण घुंघराले ब्रेसिज़ द्वारा चिह्नित एक ब्लॉक में रखा गया है।

उन्होंने इसे बदल दिया क्योंकि यह कुछ गतिशील (वर्तमान समय की तरह) में पारित करना बहुत आसान था। यह समस्या को दूर करता है क्योंकि ब्लॉक का मूल्यांकन रनटाइम पर किया जाता है। यदि आप किसी ब्लॉक का उपयोग नहीं करते हैं तो आपको यह त्रुटि मिलेगी:

बिना किसी ब्लॉक के #default_scope को कॉल करने का समर्थन हटा दिया गया है। उदाहरण के लिए default_scope where(color: 'red'), कृपया उपयोग करें default_scope { where(color: 'red') }। (वैकल्पिक रूप से आप बस self.default_scope को फिर से परिभाषित कर सकते हैं।)

जैसा कि @Dan ने अपनी टिप्पणी में उल्लेख किया है, आप इस तरह से अधिक रूखे वाक्य रचना कर सकते हैं:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

या कई स्तंभों के साथ:

class Book < ActiveRecord::Base
  default_scope { order({begin_date: :desc}, :name) }
end

धन्यवाद @ दान !


28
रेल में 4 यह भी लिखा जा सकता है जैसे default_scope { order(created_at: :desc) }कि, मेरी तरह, आप रेल सिंटैक्स को रेल में कम करने की कोशिश करते हैं। <br/> यदि आपके पास ऑर्डर करने के लिए कई कॉलम हैं और आप नए सिंटैक्स का उपयोग करना चाहते हैं, तो आपको डीईसी को लपेटने की आवश्यकता हो सकती है। इस तरह मूंछों में कॉलमdefault_scope { order({begin_date: :desc}, :name) }
डैन

1
@Dan - न केवल आपकी टिप्पणी एसक्यूएल को खत्म करती है, यह एक अधिक रूबिश वाक्य रचना है।
बी सेवन

6

आप डिफ़ॉल्ट प्रकार के आदेश को लागू करने के लिए default_scope का उपयोग कर सकते हैं http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html


6
लिंक काम कर रहा है लेकिन इसके बारे में कुछ भी नहीं है default_scope उस पृष्ठ के , क्योंकि इसे ( api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/… ) ActiveRecord::Baseमें से दर्शाया गया हैActiveRecord::Scoping::Default::ClassMethods
डैनियल रिकोव्स्की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.