दो ActiveRecord :: संबंध वस्तुओं को मिलाएं


174

मान लीजिए कि मेरे पास निम्नलिखित दो वस्तुएं हैं:

first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation  = User.where(:last_name  => 'Fünke') # ActiveRecord::Relation

क्या यह संभव है कि ActiveRecord::Relationदोनों स्थितियों को जोड़कर एक वस्तु को दोनों स्थितियों से जोड़ा जाए?

नोट: मुझे पता है कि मैं इस व्यवहार को प्राप्त करने के लिए सीटी बजा सकता हूं, जो मैं वास्तव में रुचि रखता हूं वह मामला है जहां मेरे पास दो अलग-अलग ActiveRecord::Relationऑब्जेक्ट हैं।


जवाबों:


202

यदि आप AND(चौराहे) का उपयोग करके संयोजन करना चाहते हैं , तो उपयोग करें merge:

first_name_relation.merge(last_name_relation)

आप उपयोग कर गठबंधन करने के लिए चाहते हैं OR(संघ), का उपयोग :or

first_name_relation.or(last_name_relation)

केवल ActiveRecord 5+ में; 4.2 के लिए जहां-या बैकपोर्ट स्थापित करें ।


कैसे के बारे में अगर मैं परिणाम एक ActiveRecord::Relationप्रकार होना चाहते हैं ?
न्यू अलेक्जेंड्रिया

1
@NewAlexandria हाँ, सभी मामले, रेल ऑब्जेक्ट के वर्ग के बारे में आपसे झूठ बोल रहे हैं।
एंड्रयू मार्शल 18

77
मर्ज का एक "या" संस्करण है?
आर्कोले

8
@minohimself शायद, क्योंकि यह आपके दो संबंधों के विलय का वास्तविक परिणाम है। ध्यान दें कि mergeएक चौराहा है, संघ नहीं।
एंड्रयू मार्शल

5
भविष्य के संदर्भ के लिए, #orविधि 2015 में ActiveRecord :: Relation में जोड़ा गया है, और यह रेल 5.0 का हिस्सा होगा, जो 2015 के अंत में जहाज जाएगा। यह OR ऑपरेटर को WHERE या HAVING क्लॉज़ को संयोजित करने की अनुमति देता है। आप आधिकारिक रिलीज से पहले जरूरत पड़ने पर हेड को चेकआउट कर सकते हैं। मर्ज पुल अनुरोध देखें # 16052 @Arcolye @AndrewMarshall @ Aldo-xoen-Giambelluca
क्लाउडियो फ्लोरिएनी

37

संबंध वस्तुओं को सरणियों में परिवर्तित किया जा सकता है। यह उपेक्षा बाद में उन पर किसी भी ActiveRecord विधियों का उपयोग करने में सक्षम है, लेकिन मुझे इसकी आवश्यकता नहीं थी। इसे मैने किया है:

name_relation = first_name_relation + last_name_relation

रूबी 1.9, रेल 3.2


अपडेट: अफ़सोस की बात यह है कि तारीख से विलय नहीं
डैनियल मॉरिस

68
यह एक सरणी के रूप में कार्य नहीं करता है, यह आपके संबंध को एक सरणी में परिवर्तित करता है। फिर आप उस पर ActiveRecord विधियों का उपयोग नहीं कर सकते हैं। जैसे () अब ...
Augustin Riedinger

1
यदि आप रिटर्न प्रकार के संबंध के बारे में परवाह नहीं करते हैं, तो आप first_name_relation के साथ कई परिणाम जोड़ सकते हैं last_name_relation। "|" ऑपरेटर कई संबंधों पर भी काम करता है। परिणाम मान एक सरणी है।
माइकल ज़ू

11
मूल प्रश्न यह था: "क्या दोनों संबंधों को एक ActiveRecord बनाने के लिए संयोजित करना संभव है :: संबंध वस्तु दोनों स्थितियों से युक्त?" यह जवाब एक सरणी देता है ...
कोर्टिमेस

यह कई मामलों के लिए एक उत्कृष्ट समाधान है। यदि आपको केवल लूप के माध्यम से रिकॉर्ड्स की गणना करने की आवश्यकता है (जैसे कि अगर यह एक ऐरे या ActiveRecord :: Relation है तो परवाह नहीं है) और दो प्रश्नों के ओवरहेड को ध्यान में न रखें, तो यह समस्या को स्पष्ट, सरल वाक्यविन्यास के साथ हल करता है। काश मैं इसे +2 कर पाता!
डेविड हेमपी

21

mergeवास्तव में जैसे काम नहीं करता है OR। यह सिर्फ चौराहा ( AND) है

मैं ActiveRecord से जुड़ने के लिए इस समस्या से जूझ रहा था :: एक में संबंध वस्तुएं और मुझे मेरे लिए कोई समाधान नहीं मिला।

इन दो सेटों से एक संघ बनाने की सही विधि की खोज करने के बजाय, मैंने सेटों के बीजगणित पर ध्यान केंद्रित किया। आप इसे डी मॉर्गन के कानून का उपयोग करके अलग तरीके से कर सकते हैं

ActiveRecord मर्ज विधि (और) प्रदान करता है और आप विधि या none_of (Not) का उपयोग नहीं कर सकते हैं।

search.where.none_of(search.where.not(id: ids_to_exclude).merge(search.where.not("title ILIKE ?", "%#{query}%")))

आपके यहाँ (A u B) '= A' ^ B 'है

अद्यतन: उपरोक्त समाधान अधिक जटिल मामलों के लिए अच्छा है। आपके मामले में इस तरह से पर्याप्त होगा:

User.where('first_name LIKE ? OR last_name LIKE ?', 'Tobias', 'Fünke')

15

मैं कई विषम परिस्थितियों में भी, रेल की बिल्ट-इन Arel का उपयोग करके, इसे पूरा करने में सक्षम रहा हूँ ।

User.where(
  User.arel_table[:first_name].eq('Tobias').or(
    User.arel_table[:last_name].eq('Fünke')
  )
)

यह अरेल के का उपयोग करके दोनों ActiveRecord संबंधों विलीन हो जाती है या


मर्ज, जैसा कि यहां सुझाया गया था, मेरे लिए काम नहीं किया। इसने परिणामों से संबंधित वस्तुओं का दूसरा सेट गिरा दिया।


2
यह सबसे अच्छा जवाब है, IMO। यह OR प्रकार के प्रश्नों के लिए त्रुटिपूर्ण रूप से काम करता है।
द वेकिंगट्रूथ

इस ओर इशारा करने के लिए धन्यवाद, मुझे बहुत मदद मिली। अन्य उत्तर केवल खेतों के एक छोटे उपसमुच्चय के लिए काम करते हैं, लेकिन IN स्टेटमेंट में दस हजार आईडी से ऊपर के लिए, प्रदर्शन बहुत खराब हो सकता है।
onetwopunch

1
@KeesBriggs- सच नहीं है। मैंने इसका उपयोग रेल के सभी संस्करणों में किया है 4.
6ft Dan

14

एक रत्न है जिसे active_record_union कहा जाता है जो हो सकता है कि आप देख रहे हों।

यह उदाहरण है usages निम्नलिखित है:

current_user.posts.union(Post.published)
current_user.posts.union(Post.published).where(id: [6, 7])
current_user.posts.union("published_at < ?", Time.now)
user_1.posts.union(user_2.posts).union(Post.published)
user_1.posts.union_all(user_2.posts)

साझा करने के लिए धन्यवाद। यहां तक कि चार साल अपनी पोस्ट के बाद यह मेरी ओर से एक संघ बनाने के लिए एकमात्र समाधान कर दिया गया है ransackऔर acts-as-taggable-onजब तक मेरी रखते हुए ActiveRecordउदाहरणों बरकरार।
बेंजामिन बोजको

इस रत्न का उपयोग करते समय, आपको एक ActiveRecord नहीं मिल सकता है :: संघ द्वारा लौटाया गया संबंध () कॉल यदि आपके पास मॉडल पर परिभाषित ढलान है। Readme में ActiveRecord में संघ की स्थिति देखें।
डेचम्प

9

यह है कि मैंने इसे "संभाला" है यदि आप प्रत्येक रिकॉर्ड के लिए एक पहचानकर्ता प्राप्त करने के लिए प्लक का उपयोग करते हैं, एक साथ सरणियों में शामिल होते हैं और फिर अंत में आईडी से जुड़ने वालों के लिए एक प्रश्न करते हैं:

  transaction_ids = @club.type_a_trans.pluck(:id) + @club.type_b_transactions.pluck(:id) + @club.type_c_transactions.pluck(:id)
  @transactions = Transaction.where(id: transaction_ids).limit(100)

6

यदि आपके पास एक्टिवरकॉर्ड संबंधों की एक सरणी है और उन सभी को मर्ज करना चाहते हैं, तो आप कर सकते हैं

array.inject(:merge)

array.inject(:merge)5.1.4 रेल में एक्टिवरकॉर्ड संबंधों की सरणी के लिए काम नहीं किया। लेकिन array.flatten!किया।
जिस्मिज़

0

जानवर बल इसे:

first_name_relation = User.where(:first_name => 'Tobias') # ActiveRecord::Relation
last_name_relation  = User.where(:last_name  => 'Fünke') # ActiveRecord::Relation

all_name_relations = User.none
first_name_relation.each do |ar|
  all_name_relations.new(ar)
end
last_name_relation.each do |ar|
  all_name_relations.new(ar)
end

"NoMethodError (अपरिभाषित विधि` stringify_keys '# # MyModel: 0x ...) के लिए Rails3 में, MyModel.none को MyModel.where (1 = 2) में बदलने के बाद भी, क्योंकि Rails3 में' कोई नहीं 'विधि है।
जोसेफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.