रेल्स कंट्रोलर्स में खोज, सॉर्टिंग और फ़िल्टरिंग एक दर्द हो सकता है। ElasticSearch और Solr बेहतरीन, उच्च-शक्ति वाले समाधान हैं, लेकिन एक छोटे ऐप के लिए वास्तव में बड़ी निर्भरताएं हैं।
सौभाग्य से, रेल्स में स्कोप्स शामिल हैं, जो सरल खोज, फ़िल्टरिंग और सॉर्टिंग के लिए आपको जो चाहिए उसका बहुत कुछ प्रदान कर सकते हैं। यदि आप स्कोप चेनिंग का लाभ उठाते हैं, तो आप बड़ी निर्भरताएं लिए बिना या खुद बहुत सारा दोहराव वाला खोज कोड लिखे बिना अपनी इच्छित सुविधाओं का निर्माण कर सकते हैं।
स्कोप्स के साथ खोज
एक #index मेथड की कल्पना करें जो आपके RESTful कंट्रोलर पर प्रोडक्ट्स की एक टेबल दिखाता है। प्रोडक्ट्स एक्टिव, पेंडिंग, या इनएक्टिव हो सकते हैं, एक ही स्थान पर उपलब्ध हैं, और उनका एक नाम है।
यदि आप इन प्रोडक्ट्स को फ़िल्टर करने में सक्षम होना चाहते हैं, तो आप कुछ स्कोप्स लिख सकते हैं:
class Product < ActiveRecord::Base scope :filter_by_status, -> (status) { where status: status } scope :filter_by_location, -> (location_id) { where location_id: location_id } scope :filter_by_starts_with, -> (name) { where("name like ?", "#{name}%")} end
इनमें से प्रत्येक स्कोप Product पर एक क्लास मेथड परिभाषित करता है जिसका उपयोग आप प्राप्त होने वाले परिणामों को सीमित करने के लिए कर सकते हैं।
@products = Product.filter_by_status("active").filter_by_starts_with("Ruby") # => 'Ruby' से शुरू होने वाले सभी एक्टिव प्रोडक्ट्स
आपका कंट्रोलर इन स्कोप्स का उपयोग आपके परिणामों को फ़िल्टर करने के लिए कर सकता है:
def index @products = Product.where(nil) # एक अनाम स्कोप बनाता है @products = @products.filter_by_status(params[:status]) if params[:status].present? @products = @products.filter_by_location(params[:location]) if params[:location].present? @products = @products.filter_by_starts_with(params[:starts_with]) if params[:starts_with].present? end
और अब आप केवल उन्हीं एक्टिव प्रोडक्ट्स को दिखा सकते हैं जिनके नाम 'Ruby' से शुरू होते हैं।
https://example.com/products?status=active&starts_with=Ruby
स्पष्ट रूप से, इसे कुछ सफाई की आवश्यकता है
आप देख सकते हैं कि यह कोड कैसे अनियंत्रित और दोहरावदार होने लगता है! बेशक, आप रूबी का उपयोग कर रहे हैं, इसलिए आप इसे एक लूप में डाल सकते हैं:
def index @products = Product.where(nil) filtering_params(params).each do |key, value| @products = @products.public_send("filter_by_#{key}", value) if value.present? end end private # पैरामीटर नामों की सूची जिनका उपयोग प्रोडक्ट सूची को फ़िल्टर करने के लिए किया जा सकता है def filtering_params(params) params.slice(:status, :location, :starts_with) end
एक अधिक पुन: प्रयोज्य समाधान
आप इस कोड को एक मॉड्यूल में स्थानांतरित कर सकते हैं और इसे किसी भी मॉडल में शामिल कर सकते हैं जो फ़िल्टरिंग का समर्थन करता है:
module Filterable extend ActiveSupport::Concern module ClassMethods def filter(filtering_params) results = self.where(nil) filtering_params.each do |key, value| results = results.public_send("filter_by_#{key}", value) if value.present? end results end end end
class Product include Filterable ... end
def index @products = Product.filter(params.slice(:status, :location, :starts_with)) end
अब आपके पास कंट्रोलर में एक लाइन और मॉडल में एक लाइन के साथ अपने मॉडल्स की फ़िल्टरिंग और खोज है। यह कितना आसान है? आप बिल्ट-इन order क्लास मेथड का उपयोग करके बिल्ट-इन सॉर्टिंग भी प्राप्त कर सकते हैं, लेकिन अपने खुद के स्कोप्स लिखना सॉर्टिंग के लिए शायद बेहतर विचार है। इस तरह आप इनपुट को सैनिटी-चेक कर सकते हैं।
आपको कुछ प्रयास बचाने के लिए, मैंने Filterable को एक गिस्ट में डाल दिया है। इसे अपने प्रोजेक्ट में आज़माएं, इसने मुझे बहुत समय और कोड बचाया है।
अपडेट: Jan Sandbrink को कुछ इंगित करने के लिए धन्यवाद: filtering_params में पैरामीटर्स को व्हाइटलिस्ट करना भूलना आसान है। यदि आप भूल जाते हैं, तो यह आपके ऐप को गंभीर सुरक्षा समस्याओं के लिए खोल सकता है।
इस सब से बचने के लिए, status, location, और starts_with नाम के स्कोप्स का उपयोग करने के बजाय, मैंने इस लेख को अपडेट किया है ताकि वे स्कोप्स अब filter_by_status, filter_by_location, और filter_by_starts_with नाम से जाने जाएं। वे स्पष्ट और सुरक्षित हैं।
एक महत्वपूर्ण चेतावनी
पैरामीटर्स को स्कोप्स में भेजना आपके वेब ऐप में बुनियादी खोज और फ़िल्टरिंग प्राप्त करने का एक आसान तरीका है। लेकिन यदि आप सावधान नहीं हैं, और अपने यूजर्स जो कुछ भी भेजते हैं उसे स्वीकार करते हैं, तो आपके ऐप में कुछ बहुत बुरे सुरक्षा बग हो सकते हैं।
विशेष रूप से, order SQL इंजेक्शन के लिए कमजोर है। इसलिए यदि आप अपने सॉर्ट ऑर्डर को परिभाषित करने के लिए पैरामीटर्स का उपयोग कर रहे हैं, तो आपको हमेशा उन कॉलम नामों की जांच करनी चाहिए जो आपका यूजर आपको भेज रहा है और केवल उन मानों को अनुमति दें जिन्हें आप जानते हैं कि वे सुरक्षित हैं।
Rails SQL Injection साइट आपको यह जानने में मदद करेगी कि कौन से ActiveRecord मेथड्स कमजोर हैं, ताकि आप अपने ऐप को सुरक्षित रख सकें।
क्या आप वीडियो के साथ बेहतर सीखते हैं?
आप साथी स्क्रीनकास्ट में हर कदम देख सकते हैं, एक बिल्कुल नए ऐप को शुरू करने से लेकर खोज और फ़िल्टरिंग जोड़ने तक। हम एक ऐप बनाएंगे, इसे सैंपल डेटा से भरेंगे, एक खोज फॉर्म जोड़ेंगे, और इसे हुक अप करेंगे। और आपको वीडियो के साथ सोर्स भी मिलेगा, ताकि जब आप अपने रेल्स ऐप्स में सरल खोज और फ़िल्टरिंग जोड़ें तो आप वापस रेफर कर सकें।
स्क्रीनकास्ट के बारे में यहाँ और जानें!