रेल 4 तरह क्वेरी - ActiveRecord उद्धरण जोड़ता है


127

मैं इस तरह से एक क्वेरी करने की कोशिश कर रहा हूं

def self.search(search, page = 1 )
  paginate :per_page => 5, :page => page,
    :conditions => ["name LIKE '%?%' OR postal_code like '%?%'", search, search],   order => 'name'
end

लेकिन जब इसे चलाया जाता है, तो कुछ उद्धरणों को जोड़ा जाता है जिसके कारण sql स्टेटमेंट ऐसा होता है

SELECT COUNT(*)
FROM "schools" 
WHERE (name LIKE '%'havard'%' OR postal_code like '%'havard'%')):

तो आप मेरी समस्या देख सकते हैं। मैं रेल्स 4 और पोस्टग्रैस 9 का उपयोग कर रहा हूं, जिनमें से मैंने कभी भी इसका उपयोग नहीं किया है यदि इसकी और एक्टिवरकॉर्ड चीज या संभवतः पोस्टग्रेज चीज नहीं है।

मैं इसे कैसे सेट कर सकता हूं ताकि मुझे '%my_search%'अंत क्वेरी में पसंद आए?

जवाबों:


228

आपके प्लेसहोल्डर को एक स्ट्रिंग द्वारा बदल दिया गया है और आप इसे सही तरीके से नहीं संभाल रहे हैं।

बदलने के

"name LIKE '%?%' OR postal_code LIKE '%?%'", search, search

साथ में

"name LIKE ? OR postal_code LIKE ?", "%#{search}%", "%#{search}%"

6
क्या यह SQL इंजेक्शन की चपेट में नहीं है? मेरा मतलब है, क्या वे searchतार संजीवित हैं?
jdscosta91 17

6
@ jdscosta91 में सैनिटाइजिंग का ?ख्याल कहाँ रखा जाएगा
house9

7
@ हाउस 9 इंस्टेंस के अंदर %और _अंदर searchइस दृष्टिकोण के तहत स्वच्छता नहीं होगी।
बैरी केली

8
उपयोग करते समय '?' इस तरह रेल में यह एक पैरामीटर क्वेरी में बदल जाता है। पैरामीटर के भीतर का डेटा सैनिटाइज्ड (%) नहीं है, लेकिन क्वेरी से बाहर संदर्भ को बदलना और इसे संसाधित SQL स्टेटमेंट में बदलना असंभव है।
डेविड होइल्ज़र

50

conditionsरेल 2 से सिंटैक्स का उपयोग करने के बजाय , रेल्स 4 की whereविधि का उपयोग करें:

def self.search(search, page = 1 )
  wildcard_search = "%#{search}%"

  where("name ILIKE :search OR postal_code LIKE :search", search: wildcard_search)
    .page(page)
    .per_page(5)
end

नोट: उपरोक्त के बजाय पैरामीटर सिंटैक्स का उपयोग करता है? प्लेसहोल्डर: इन दोनों को एक ही वर्ग उत्पन्न करना चाहिए।

def self.search(search, page = 1 )
  wildcard_search = "%#{search}%"

  where("name ILIKE ? OR postal_code LIKE ?", wildcard_search, wildcard_search)
    .page(page)
    .per_page(5)
end

नोट: ILIKEनाम के लिए उपयोग करना - LIKE का असंवेदनशील संस्करण पोस्टग्रेज करता है


क्या यह अभी भी रेल 5 के लिए वैध है? क्योंकि अगर मैंने Movie.where("title ILIKE :s", s: search_string)इसे SELECT 1 AS one FROM "movies" WHERE (title ILIKE 'test') LIMIT $1ActiveRecord (रेल 5.1.6) द्वारा अनुवादित किया है - कृपया ध्यान दें कि ILIKE के बाद कोई प्रतिशत प्रतीक नहीं है)
sekmo

@sekmo - यह काम करना चाहिए, प्रतिशत search_stringचर में जाएगा। मुझे लगता है कि SELECT 1 AS oneआउटपुट केवल रेल कंसोल में है या आप उपयोग कर रहे हैं limit(1)? FYI करें: रेल 5.1.6 के पास सुरक्षा मुद्दे हैं, इसके बजाय 5.1.6.2 या 5.1.7 का उपयोग करें
house9

22

जबकि स्ट्रिंग प्रक्षेप काम करेगा, जैसा कि आपका प्रश्न 4 निर्दिष्ट करता है, आप इसके लिए Arel का उपयोग कर सकते हैं और अपने ऐप डेटाबेस को एगोस्टिक रख सकते हैं।

def self.search(query, page=1)
  query = "%#{query}%"
  name_match = arel_table[:name].matches(query)
  postal_match = arel_table[:postal_code].matches(query)
  where(name_match.or(postal_match)).page(page).per_page(5)
end

वास्तव में विशेषताओं की सूची के साथ गतिशील रूप से ऐसा करने के लिए एक
फेक

अनटाइटेड, हालांकि यह कुछ इस तरह हो सकता है: गुंजाइश search_attributes, -> (क्वेरी, विशेषताएँ) {arel_attributes = विशेषताएँ.map {| a | arel_table [a]} arel_queries = arel_attributes.map {| एक | a.matches (क्वेरी)} जहां (arel_queries.reduce {| Res, q | res.or q})} पर लौटें
पेड्रो रोलो

8

ActiveRecord यह जानने के लिए पर्याप्त चतुर है कि पैरामीटर द्वारा निर्दिष्ट ?स्ट्रिंग एक है, और इसलिए यह इसे एकल उद्धरण में संलग्न करता है। आप एक पोस्ट के अनुसार आवश्यक प्रतीकों के साथ स्ट्रिंग को पैड करने के लिए रूबी स्ट्रिंग प्रक्षेप का उपयोग करने का सुझाव दे सकते हैं% । हालाँकि, यह आपको SQL-injection (जो खराब है) को उजागर कर सकता है। मेरा सुझाव है कि आप CONCAT()स्ट्रिंग को तैयार करने के लिए एसक्यूएल फ़ंक्शन का उपयोग करें जैसे:

"name LIKE CONCAT('%',?,'%') OR postal_code LIKE CONCAT('%',?,'%')", search, search)


मैंने इसे एक आवेदन में लागू किया और इसने बहुत अच्छा काम किया। धन्यवाद जॉन।
fuzzygroup

इंजेक्शन के बारे में, नहीं, यह नहीं है और किसी भी मामले में इससे कोई फर्क नहीं पड़ता। स्ट्रिंग को एसक्यूएल में डाला गया है और रेल को पहले से मान्य किया जाना चाहिए (इससे कोई फर्क नहीं पड़ता कि कोई %जोड़ा गया है / पूर्व निर्धारित किया गया है या नहीं)। या तो यह अपेक्षा के अनुरूप काम करता है या रेल के दोनों मामलों को प्रभावित करने वाला एक प्रमुख बग है।
estani

5

प्रयत्न

 def self.search(search, page = 1 )
    paginate :per_page => 5, :page => page,
      :conditions => ["name LIKE  ? OR postal_code like ?", "%#{search}%","%#{search}%"],   order => 'name'
  end

अधिक जानकारी के लिए AREL शर्तों पर डॉक्स देखें ।


हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.