मैं रेल में स्वचालित रूप से एक has_many संबंध कैसे बनाऊं?


96

यह एक बहुत ही सरल प्रश्न लगता है, लेकिन मैंने कहीं भी इसका उत्तर नहीं देखा है।

रेल में अगर आपके पास:

class Article < ActiveRecord::Base 
  has_many :comments 
end 
class Comments < ActiveRecord::Base 
  belongs_to :article 
end

आप कुछ इस तरह से टिप्पणियों का आदेश क्यों नहीं दे सकते:

@article.comments(:order=>"created_at DESC")

यदि आप इसे बहुत संदर्भित करना चाहते हैं तो नामांकित कार्यक्षेत्र भी काम करता है और यहां तक ​​कि लोग इस तरह से सामान बनाते हैं:

@article.comments.sort { |x,y| x.created_at <=> y.created_at }

लेकिन कुछ मुझे बताता है कि यह सरल होना चाहिए। मैं क्या खो रहा हूँ?


सावधान रहें, आप एक अप्रत्याशित विधि का उपयोग कर रहे हैं: @ article.comments (पुनः लोड = गलत) एक कैश-मिस को मजबूर करने के लिए है (किसी संबंध को फिर से लोड करने के लिए मजबूर करने के लिए)। यदि आप एक हैश प्रदान करते हैं, तो यह @ article.comments (सत्य) के समान है। का उपयोग करने के लिए मत भूलना .all (: आदेश => '...')। मेरे पैर को कुछ समय पहले ही तोड़ दिया।
मार्सेल जैकवर्थ

जवाबों:


152

आप has_manyस्वयं पर एक विकल्प के साथ नंगे संग्रह के लिए क्रमबद्ध क्रम निर्दिष्ट कर सकते हैं :

class Article < ActiveRecord::Base 
  has_many :comments, :order => 'created_at DESC'
end 
class Comment < ActiveRecord::Base 
  belongs_to :article 
end

या, यदि आप छँटाई का एक सरल, गैर-डेटाबेस तरीका चाहते हैं, तो Sort_by का उपयोग करें :

article.comments.sort_by &:created_at

ActiveRecord- क्रमबद्ध करने के तरीकों के साथ इसे एकत्रित करना:

article.comments.find(:all, :order => 'created_at DESC')
article.comments.all(:order => 'created_at DESC')

आपका माइलेज अलग-अलग हो सकता है: उपरोक्त समाधानों की प्रदर्शन विशेषताओं में बेतहाशा बदलाव आएगा कि आप पहली बार में डेटा कैसे प्राप्त कर रहे हैं और रूबी आप अपने ऐप को चलाने के लिए किसका उपयोग कर रहे हैं।


धन्यवाद, "सब" शायद सबसे सरल है। अच्छी चीज़!
ब्रायन आर्मस्ट्रांग

58
रेल 4 में, आदेश विकल्प हटा दिया गया है। -> { order(created_at: :desc) }इसके बजाय एक लैम्ब्डा का उपयोग करें । देखें: stackoverflow.com/questions/18284606/…
d_rail

यह रेल 4 के साथ पदावनत हुआ, देखें stackoverflow.com/questions/18284606/…
bjelli

41

रेल 4 के रूप में, आप क्या करेंगे:

class Article < ActiveRecord::Base 
  has_many :comments, -> { order(created_at: :desc) }
end 
class Comment < ActiveRecord::Base 
  belongs_to :article 
end

एक has_many :throughसंबंध के लिए तर्क आदेश मायने रखता है (यह दूसरा होना चाहिए):

class Article
  has_many :comments, -> { order('postables.sort' :desc) }, 
           :through => :postable
end

आप हमेशा एक ही क्रम में पहुँच टिप्पणी करना चाहते हैं, तो कोई संदर्भ बात आप भी के माध्यम से ऐसा कर सकता है default_scopeके भीतर Commentकी तरह:

class Comment < ActiveRecord::Base 
  belongs_to :article 
  default_scope { order(created_at: :desc) }
end

हालाँकि यह इस प्रश्न में चर्चा किए गए कारणों के लिए समस्याग्रस्त हो सकता है ।

रेल 4 से पहले आप orderरिश्ते की कुंजी के रूप में निर्दिष्ट कर सकते हैं , जैसे:

class Article < ActiveRecord::Base 
  has_many :comments, :order => 'created_at DESC'
end 

जैसा कि जिम ने उल्लेख किया है कि आप भी उपयोग कर सकते हैं sort_by परिणाम प्राप्त बाद हालांकि आकार के किसी भी परिणाम सेट में यह SQL / ActiveRecord के माध्यम से आपके ऑर्डर करने की तुलना में काफी धीमा (और बहुत अधिक मेमोरी का उपयोग करेगा)।

यदि आप कुछ ऐसा कर रहे हैं, जिसमें डिफ़ॉल्ट ऑर्डर जोड़ना किसी कारण से बोझिल है या आप कुछ मामलों में अपने डिफ़ॉल्ट को ओवरराइड करना चाहते हैं, तो इसे लाने की क्रिया में ही निर्दिष्ट करना तुच्छ है:

sorted = article.comments.order('created_at').all

1
मैं इसे स्वयं लाने की क्रिया में कहां निर्दिष्ट कर सकता हूं? क्या मैं मॉडल में एक विधि को ओवरराइड करता हूं?
विट

@Wit - आप .order()अंतिम उदाहरण की तरह विधि श्रृंखला में जोड़ सकते हैं । क्या यह आप पूछ रहे हैं?
मैट सैंडर्स

मुझे क्षमा करें। मुझे याद नहीं कि मैं क्या हासिल करना चाह रहा था।
बुद्धि

1
बहुरंगी उदाहरण के माध्यम से has_many, यहाँ सुपर सहायक है!
विजय

7

यदि आप रेल 2.3 का उपयोग कर रहे हैं और इस ऑब्जेक्ट के सभी संग्रह के लिए समान डिफ़ॉल्ट ऑर्डरिंग का उपयोग करना चाहते हैं तो आप अपने संग्रह को ऑर्डर करने के लिए default_scope का उपयोग कर सकते हैं।

class Student < ActiveRecord::Base
  belongs_to :class

  default_scope :order => 'name'

end

फिर अगर तुम बुलाओ

@students = @class.students

उन्हें आपके default_scope के अनुसार ऑर्डर दिया जाएगा। एक बहुत ही सामान्य अर्थ क्रम में टीबीएच डिफ़ॉल्ट स्कोप का एकमात्र अच्छा उपयोग है।


रेल 4 के रूप में यह अनुपालन नहीं है। सही रेल 4 सिंटैक्स के लिए यह समाधान देखें: stackoverflow.com/questions/18506038/rails-4-default-scope
Kees Briggs

6

आप अपनी वस्तुओं को प्राप्त करने और उन्हें क्रमबद्ध करने के लिए ActiveRecord की खोज विधि का उपयोग कर सकते हैं।

  @article.comments.find(:all, :order => "created_at DESC")

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html


3
या आशुलिपि विधि @ article.comments.all (: आदेश => 'created_at DESC')
एरिक

0

और अगर आपको कुछ अतिरिक्त तर्कों को पारित करने की आवश्यकता है जैसे dependent: :destroyया जो भी हो, तो आपको लंबोदर के बाद इस तरह से लोगों को जोड़ना चाहिए:

class Article < ActiveRecord::Base 
  has_many :comments, -> { order(created_at: :desc) }, dependent: :destroy
end
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.