[Ruby-on-rails] रेल: स्कोप पूछताछ के साथ या इसके बजाय चेन कैसे करें?


Answers

ARel प्रयोग करें

t = Person.arel_table

results = Person.where(
  t[:name].eq("John").
  or(t[:lastname].eq("Smith"))
)
Question

मैं Rails3, ActiveRecord का उपयोग कर रहा हूँ

बस सोच रहा हूं कि मैं स्कॉप्स को या इसके बजाय कथन के साथ कैसे श्रृंखलाबद्ध कर सकता हूं।

जैसे

Person.where(:name => "John").where(:lastname => "Smith")

वह आम तौर पर नाम = 'जॉन' और अंतिम नाम = 'स्मिथ' देता है, लेकिन मुझे यह पसंद है:

नाम = 'जॉन' या अंतिम नाम = 'स्मिथ'




तो मूल प्रश्न का उत्तर, क्या आप 'और' के बजाय 'या' के साथ स्कोप में शामिल हो सकते हैं "ऐसा नहीं हो सकता"। लेकिन आप कोड को पूरी तरह से अलग-अलग दायरे या क्वेरी को सौंप सकते हैं जो नौकरी करता है, या ActiveRecord जैसे मेटावेयर या स्क्वाइल से एक अलग ढांचे का उपयोग कर सकता है। मेरे मामले में उपयोगी नहीं है

मैं pg_search द्वारा उत्पन्न एक गुंजाइश हूं, जो चयन से थोड़ी अधिक है, इसमें एएससी द्वारा आदेश शामिल है, जो एक स्वच्छ संघ की गड़बड़ी करता है। मैं इसे एक हस्तशिल्प के साथ 'या' करना चाहता हूं जो सामान करता है जो मैं pg_search में नहीं कर सकता। तो मुझे इसे ऐसा करना पड़ा।

Product.find_by_sql("(#{Product.code_starts_with('Tom').to_sql}) union (#{Product.name_starts_with('Tom').to_sql})")

मैं स्कॉप्स को एसक्यूएल में बदलता हूं, प्रत्येक के चारों ओर ब्रैकेट डालता हूं, उन्हें एक साथ जोड़ता हूं और फिर sql जेनरेट का उपयोग करके find_by_sql ढूंढता हूं। यह थोड़ा बकवास है, लेकिन यह काम करता है।

नहीं, मुझे मत बताओ मैं pg_search में "विरुद्ध: [: name,: code]" का उपयोग कर सकता हूं, मैं इसे ऐसा करना चाहता हूं, लेकिन 'नाम' फ़ील्ड एक हैस्टोर है, जो pg_search संभाल नहीं सकता अभी तक। तो नाम से गुंजाइश हाथ से तैयार की जानी चाहिए और फिर pg_search दायरे के साथ मिलकर बनना होगा।




आप SQL कोड के साथ अपना कोड मिश्रण न करने के लिए MetaWhere मणि का भी उपयोग कर सकते हैं:

Person.where((:name => "John") | (:lastname => "Smith"))



मेटावेयर के लिए यह एक अच्छा उम्मीदवार होगा यदि आप रेल 3.0+ का उपयोग कर रहे हैं, लेकिन यह रेल 3.1 पर काम नहीं करता है। आप इसके बजाय squeel को आजमा सकते हैं। यह एक ही लेखक द्वारा बनाया गया है। यहां बताया गया है कि आप एक OR आधारित श्रृंखला कैसे करेंगे:

Person.where{(name == "John") | (lastname == "Smith")}

आप कई अन्य squeel बीच मिश्रण और मिलान कर सकते squeel




यदि कोई इस के लिए एक अद्यतन उत्तर की तलाश में है, तो ऐसा लगता है कि इसे रेल में लाने के लिए मौजूदा पुल अनुरोध है: https://github.com/rails/rails/pull/9052

ActiveRecord के लिए @ j-mcnally के बंदर पैच के लिए धन्यवाद ( https://gist.github.com/j-mcnally/250eaaceef234dd8971b ) आप निम्न कार्य कर सकते हैं:

Person.where(name: 'John').or.where(last_name: 'Smith').all

या तो अधिक मूल्यवान है OR श्रृंखला के साथ श्रृंखला के लिए क्षमता:

scope :first_or_last_name, ->(name) { where(name: name.split(' ').first).or.where(last_name: name.split(' ').last) }
scope :parent_last_name, ->(name) { includes(:parents).where(last_name: name) }

फिर आप सभी व्यक्तियों को पहले या अंतिम नाम या जिनके माता-पिता के साथ अंतिम नाम मिल सकते हैं

Person.first_or_last_name('John Smith').or.parent_last_name('Smith')

इसका उपयोग करने के लिए सबसे अच्छा उदाहरण नहीं है, लेकिन सिर्फ सवाल के साथ फिट करने की कोशिश कर रहा है।




रेल 4

scope :combined_scope, -> { where("name = ? or name = ?", 'a', 'b') }



इन संबंधित प्रश्नों को भी देखें: here , here और here

coderwall.com/p/dgv7ag/… और इस मूल उत्तर के आधार पर रेल 4 के लिए

Person
  .unscoped # See the caution note below. Maybe you want default scope here, in which case just remove this line.
  .where( # Begin a where clause
    where(:name => "John").where(:lastname => "Smith")  # join the scopes to be OR'd
    .where_values  # get an array of arel where clause conditions based on the chain thus far
    .inject(:or)  # inject the OR operator into the arels 
    # ^^ Inject may not work in Rails3. But this should work instead:
    .joins(" OR ")
    # ^^ Remember to only use .inject or .joins, not both
  )  # Resurface the arels inside the overarching query

अंत में आलेख की सावधानी बरतें:

रेल 4.1+

रेल 4.1 एक नियमित दायरे के रूप में डिफ़ॉल्ट_स्कोप का इलाज करता है। डिफॉल्ट स्कोप (यदि आपके पास कोई है) जहां_values ​​परिणाम में शामिल है और इंजेक्ट (: या) डिफ़ॉल्ट दायरे और आपके wheres के बीच जोड़ या कथन होगा। यह बुरी बात है।

इसे हल करने के लिए, आपको केवल क्वेरी को रद्द करने की आवश्यकता है।




मेरे लिए (रेल 4.2.5) यह केवल इस तरह काम करता है:

{ where("name = ? or name = ?", a, b) }