5

मैं 4.2 रेल के लिए एक रेल एप्लिकेशन पोर्टिंग कर रहा हूँ। इस रेल ऐप में एसोसिएशन में कुछ जटिल मैनुअल एसक्यूएल कोड शामिल हैं - आंशिक रूप से डीबी ऑप्टिमाइज़ेशन (उदाहरण के लिए जॉइन के बजाय उप-चयन) के कारण, आंशिक रूप से लेखन (रेल 3.0) के समय कोई व्यवहार्य विकल्प नहीं है, आंशिक रूप से निश्चित रूप से ज्ञान की कमी के कारण (मुझे उम्मीद है, कम से कम - यह हल करना आसान होगा)।Porting जटिल has_many रिश्तों रेल के लिए> 4.1 (finder_sql के बिना)

उदाहरण: एक आंतरिक संदेश वर्ग। संदेशों को उपयोगकर्ताओं के बीच भेजा जा सकता है (आंतरिक मैसेज के प्राप्तकर्ता, और संदेशों के 'हटाना', InternalMessagesRecipients में संग्रहीत हैं, क्योंकि कई हो सकते हैं) और उन्हें पढ़ा जा सकता है, जवाब दिया जा सकता है और हटाया जा सकता है। संघ इस तरह दिखता है:

class User < AR::Base 
    has_many :internal_messages, 
     :finder_sql => "SELECT DISTINCT(internal_messages.id), internal_messages.* FROM internal_messages " + 
      ' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' + 
      ' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}', 
     :counter_sql => 'SELECT count(DISTINCT(internal_messages.id)) FROM internal_messages ' + 
      ' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' + 
      ' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}' 
    # ... 
end 

महत्वपूर्ण हिस्सा "या" अंत में खंड है - यह संघ मैं दोनों प्राप्त और संदेश है, जो उपयोगकर्ता तालिका अलग से साथ शामिल हो गए हैं भेजा प्राप्त करना चाहते हैं के साथ:

has_many :sent_messages, -> { where(:sender_deleted_at => nil) }, :class_name => 'InternalMessage', :foreign_key => 'sender_id' #, :include => :sender 
    has_many :internal_messages_recipients, :foreign_key => 'recipient_id' 
    has_many :rcvd_messages, :through => :internal_messages_recipients, :source => :internal_message, :class_name => 'InternalMessage' 

एक आंतरिक संदेश के बाद कई प्राप्तकर्ता हो सकते हैं (और प्रेषक को भी भेजा जा सकता है)।

प्रश्न: मैं इस finder_sql को रेल 4.2 संगत has_many परिभाषा में कैसे पोर्ट करूं?

उत्तर

4

अद्यतन

मैंने कुछ समय पहले पता चला कि यह कोई मतलब नहीं है। has_many रिश्ते में कम से कम एक दिशा में इंजेक्शन कनेक्शन होना चाहिए, इसलिए SQL खंड में "OR" कोई समझ नहीं आता है। CREATE ऑपरेशन को एक नया रिकॉर्ड बनाने के लिए कौन सी शर्त को संतुष्ट करने का निर्णय लेना चाहिए? यह संबंध केवल परिभाषा द्वारा पढ़ा जाता है और इसलिए यह has_many संबंध नहीं है।

इस मामले में, एक साधारण वर्ग विधि (या गुंजाइश) has_many के बजाय सही जवाब होगा। श्रेणीबद्ध करने के लिए कई प्रश्नों से परिणाम

def internal_messages 
    InternalMessage.where(id: sent_message_ids + received_message_ids) 
end 

की तरह कुछ का उपयोग जिसके परिणामस्वरूप वस्तु chainable रखने के लिए (अर्थात @user.internal_messages.by_date आदि)

+0

बेशक, इस अवर है अगर आप परिणामों का Memoization चाहते हैं, खासकर इसलिए वे 'रीलोड' के साथ काम करते हैं। विदेशी संबंधों के बिना इन रिश्तों को बनाए रखने के लिए रेल पाने का कोई तरीका है? – duane

3

proc कि गुंजाइश के रूप में एसक्यूएल स्ट्रिंग दर्रा।

has_many :internal_messages, -> { proc { "SELECT DISTINCT(internal_messages.id), internal_messages.* FROM internal_messages " + 
     ' LEFT JOIN internal_messages_recipients ON internal_messages.id=internal_messages_recipients.internal_message_id' + 
     ' WHERE internal_messages.sender_id = #{id} OR internal_messages_recipients.recipient_id = #{id}' } } 
+0

ठीक है, धन्यवाद। Counter_sql के बारे में कैसे? अब और आवश्यकता नहीं है? रेल 3 के साथ DISTINCT की वजह से counter_sql का उपयोग नहीं करते समय मुझे SQL त्रुटियां मिलती थीं। – Jens

+1

मैंने कभी अपने आप से ऐसा नहीं किया है लेकिन [यह स्टैक ओवरफ्लो उत्तर] (http://stackoverflow.com/questions/22988321/replacement-for-has-many-counter-sql-in-rails-4-1) कहते हैं कि आप has_many को दिए गए ब्लॉक के अंदर अपनी खुद की गिनती विधि को परिभाषित कर सकते हैं। तो मुझे लगता है कि आप कुछ डीफ गिनती proxy_association.owner.class.count_by_sql ("आपका SQL यहां") कर सकते हैं; ब्लॉक में अंत '। – tyamagu2

+4

अद्यतन: रेल 4.2.5.1, रूबी 2.3.1p112 'has_many: वार्ता, -> {proc {" SOME SQL "}}' NoMethodError: # Dimitri

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