रेल नियंत्रकों में खोजना, छांटना और फ़िल्टर करना एक दर्द हो सकता है। ElasticSearch और Solr महान, उच्च-शक्ति वाले समाधान हैं, लेकिन वास्तव में एक छोटे ऐप के लिए बड़ी निर्भरताएं हैं।
सौभाग्य से, रेल में स्कोप शामिल हैं, जो आपको सरल खोज, फ़िल्टरिंग और सॉर्टिंग के लिए बहुत कुछ प्रदान कर सकते हैं। यदि आप स्कोप चेनिंग का लाभ उठाते हैं, तो आप बड़ी निर्भरता के बिना या स्वयं दोहराए जाने वाले खोज कोड को लिखे बिना अपनी इच्छित सुविधाओं का निर्माण कर सकते हैं।
स्कोप के साथ खोजना
एक #index
की कल्पना करें आपके रेस्टफुल कंट्रोलर पर विधि जो उत्पादों की एक तालिका दिखाती है। उत्पाद सक्रिय, लंबित या निष्क्रिय हो सकते हैं, एक ही स्थान पर उपलब्ध हैं, और उनका एक नाम है।
यदि आप इन उत्पादों को फ़िल्टर करने में सक्षम होना चाहते हैं, तो आप कुछ क्षेत्र लिख सकते हैं:
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
इनमें से प्रत्येक क्षेत्र उत्पाद पर एक वर्ग पद्धति को परिभाषित करता है जिसका उपयोग आप वापस प्राप्त परिणामों को सीमित करने के लिए कर सकते हैं।
@products = Product.filter_by_status("active").filter_by_starts_with("Ruby") # => All active products whose names start with 'Ruby'
आपका नियंत्रक आपके परिणामों को फ़िल्टर करने के लिए इन क्षेत्रों का उपयोग कर सकता है:
def index
@products = Product.where(nil) # creates an anonymous scope
@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
और अब आप 'रूबी' से शुरू होने वाले नामों के साथ केवल सक्रिय उत्पाद दिखा सकते हैं।
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
# A list of the param names that can be used for filtering the Product list
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
. डाला एक सार में। इसे अपने स्वयं के प्रोजेक्ट में आज़माएं, इसने मेरा बहुत समय और कोड बचाया है।
अपडेट करें: कुछ इंगित करने के लिए जन सैंडब्रिंक का धन्यवाद:filtering_params
में पैरा को श्वेतसूची में रखना आसान है . यदि आप भूल जाते हैं, तो यह आपके ऐप को गंभीर . तक खोल सकता है सुरक्षा समस्याएं।
इन सब से बचने के लिए, status
. नाम के दायरे का उपयोग करने के बजाय , location
, और starts_with
, मैंने इस लेख को उन क्षेत्रों में अपडेट किया है जिनका नाम अब filter_by_status
. रखा गया है , filter_by_location
, और filter_by_starts_with
. वे इस तरह अधिक स्पष्ट और सुरक्षित हैं।
एक महत्वपूर्ण चेतावनी
अपने वेब ऐप में बुनियादी खोज और फ़िल्टरिंग प्राप्त करने का एक आसान तरीका स्कोप को पैरामीटर भेजना है। लेकिन यदि आप सावधान नहीं हैं, और आपके उपयोगकर्ता जो कुछ भी आपको भेजते हैं उसे स्वीकार करते हैं, तो आपके ऐप में कुछ बहुत खराब सुरक्षा बग हो सकते हैं।
विशेष रूप से, order
एसक्यूएल इंजेक्शन के लिए कमजोर है। इसलिए यदि आप अपने सॉर्ट क्रम को परिभाषित करने के लिए पैराम का उपयोग कर रहे हैं, तो आपको हमेशा . करना चाहिए उन कॉलम नामों की जांच करें जिन्हें आपका उपयोगकर्ता आपको भेज रहा है और केवल उन मानों को अनुमति दें जिन्हें आप जानते हैं कि सुरक्षित हैं।
रेल एसक्यूएल इंजेक्शन साइट आपको यह जानने में मदद करेगी कि कौन सी ActiveRecord विधियां असुरक्षित हैं, ताकि आप अपने ऐप को सुरक्षित रख सकें।
क्या आप वीडियो से बेहतर सीखते हैं?
आप एक नया ऐप शुरू करने से लेकर खोज और फ़िल्टरिंग जोड़ने तक, सहयोगी स्क्रीनकास्ट में हर कदम देख सकते हैं। हम एक ऐप बनाएंगे, उसे नमूना डेटा से भरेंगे, एक खोज फ़ॉर्म जोड़ेंगे और उसे जोड़ेंगे। और आपको वीडियो के साथ स्रोत मिल जाएगा, ताकि जब आप अपने स्वयं के रेल ऐप्स में सरल खोज और फ़िल्टरिंग जोड़ते हैं तो आप वापस देख सकते हैं।
स्क्रीनकास्ट के बारे में यहां और जानें!