2013-04-05 9 views
13

मैं निम्नलिखित मॉडल है:रेल संघों has_one नवीनतम रिकॉर्ड

class Section < ActiveRecord::Base 
    belongs_to :page 
    has_many :revisions, :class_name => 'SectionRevision', :foreign_key => 'section_id' 
    has_many :references 

    has_many :revisions, :class_name => 'SectionRevision', 
         :foreign_key => 'section_id' 

    delegate :position, to: :current_revision 

    def current_revision 
    self.revisions.order('created_at DESC').first 
    end 
end 

कहाँ current_revision सबसे हाल ही में बनाई गई revision है। क्या current_revision को एक एसोसिएशन में बदलना संभव है ताकि मैं Section.where("current_revision.parent_section_id = '1'") जैसे क्वेरी कर सकूं? या मुझे वर्चुअल रूप से या एसोसिएशन के माध्यम से बनाने की कोशिश करने के बजाय अपने डेटाबेस में current_revision कॉलम जोड़ना चाहिए?

उत्तर

2

मैं समझता हूं कि आप उन अनुभागों को प्राप्त करना चाहते हैं जहां प्रत्येक अनुभाग के अंतिम संशोधन में parent_section_id = 1 है;

मेरे पास एक समान स्थिति है, सबसे पहले, यह एसक्यूएल है (कृपया श्रेणियों के रूप में श्रेणियां, संशोधन के रूप में पोस्ट करें और user_id को parent_section_id -sorry के रूप में पोस्ट करें यदि मैं आपकी ज़रूरत के लिए कोड नहीं लेता लेकिन मुझे करना है जाना):

SELECT categories.*, MAX(posts.id) as M 
FROM `categories` 
INNER JOIN `posts` 
ON `posts`.`category_id` = `categories`.`id` 
WHERE `posts`.`user_id` = 1 
GROUP BY posts.user_id 
having M = (select id from posts where category_id=categories.id order by id desc limit 1) 

और इस रेल में क्वेरी है:

Category.select("categories.*, MAX(posts.id) as M").joins(:posts).where(:posts => {:user_id => 1}).group("posts.user_id").having("M = (select id from posts where category_id=categories.id order by id desc limit 1)") 

यह काम करता है, यह बदसूरत है, मुझे लगता है कि सबसे अच्छा तरीका है क्वेरी "कट" करने के लिए है, लेकिन भी अगर आपके पास कई वर्ग जो एक समस्या होगी जबकि उन्हें लूप करना; आप इस क्वेरी को स्थिर विधि में भी रख सकते हैं, और साथ ही, आपका पहला विचार, आपके अनुभाग तालिका के अंदर एक revision_id क्वेरी को अनुकूलित करने में मदद करेगा, लेकिन सामान्यीकरण (कभी-कभी इसकी आवश्यकता होती है) छोड़ देगा, और आपको होना होगा इस क्षेत्र को अद्यतन करते समय जब उस अनुभाग के लिए एक नया संशोधन बनाया जाता है (इसलिए यदि आप एक विशाल डेटाबेस में बहुत से संशोधन कर रहे हैं तो शायद यह एक बुरा विचार होगा यदि आपके पास धीमी सर्वर है ...)

अद्यतन मैं वापस कर रहा हूँ hehe, मैं कुछ परीक्षण कर रहा था, और इस बाहर की जाँच:

def last_revision 
    revisions.last 
end 

def self.last_sections_for(parent_section_id) 
    ids = Section.includes(:revisions).collect{ |c| c.last_revision.id rescue nil }.delete_if {|x| x == nil} 

    Section.select("sections.*, MAX(revisions.id) as M") 
     .joins(:revisions) 
     .where(:revisions => {:parent_section_id => parent_section_id}) 
     .group("revisions.parent_section_id") 
     .having("M IN (?)", ids) 
end 

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

+0

बहुत बढ़िया होगा, धन्यवाद! –

14

आप इसे एक एसोसिएशन में बदल सकते हैं, लेकिन आमतौर पर has_one या belongs_to एसोसिएशन के लिए ऑर्डर करने पर अक्सर प्रश्नों पर इस्तेमाल होने पर गलत तरीके से व्याख्या की जाती है। अपने प्रश्न में, जब आप एक संघ में बदल जाते हैं कि, कि हो सकता है

has_one :current_revision, class_name: 'SectionRevision', foreign_key: :section_id, order: 'created_at DESC' 

इस के साथ समस्या यह है कि जब आप अन्य प्रश्नों के साथ इस गठबंधन करने के लिए प्रयास करते हैं, यह आम तौर पर आप गलत रिकॉर्ड दे देंगे।

>> record.current_revision 
    # gives you the last revision 
>> record.joins(:current_revision).where(section_revisions: { id: 1 }) 
    # searches for the revision where the id is 1 ordered by created_at DESC 

तो मैं आपको इसके बजाय current_revision_id जोड़ने का सुझाव देता हूं।

+0

सुंदर यह वही है जो मैं ढूंढ रहा था! –

+0

यदि आपके पास 'section_revisions पर शून्य बाधा है।section_id', has_one सहायक 'record.create_current_revision' (या' record.build_current_revision') का उपयोग न करें या आपको मौजूदा संबंधित current_revision को हटाने में विफल हो जाएगा। इसके विदेशी कुंजी को शून्य पर सेट करने के बाद रिकॉर्ड सहेजने में असफल रहा। 'इसके बजाय, हमेशा' record.section_revisions.create' का उपयोग करें, जो तब नया 'current_revision' –

21

एक has_many पर पिछले पाने के लिए आपको, @jvnill को छोड़कर संघ के लिए एक आदेश के साथ एक गुंजाइश जोड़ने समान कुछ करना चाहता हूँ होगा:

has_one :current_revision, -> { order created_at: :desc }, 
    class_name: 'SectionRevision', foreign_key: :section_id 

यह आपको सबसे हाल ही में संशोधन सुनिश्चित करेगा डेटाबेस से

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