Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

ค้นหาและกรองรางรุ่นโดยไม่ทำให้ตัวควบคุมของคุณบวม

การค้นหา การจัดเรียง และการกรองในตัวควบคุม Rails อาจเป็นเรื่องยุ่งยาก ElasticSearch และ Solr เป็นโซลูชันที่มีประสิทธิภาพสูงและยอดเยี่ยม แต่เป็นการพึ่งพาอาศัยกันอย่างมากสำหรับแอปขนาดเล็ก

โชคดีที่ Rails มีขอบเขตซึ่งสามารถให้สิ่งที่คุณต้องการมากมายสำหรับการค้นหา การกรอง และการเรียงลำดับอย่างง่าย หากคุณใช้ประโยชน์จากการโยงขอบเขต คุณสามารถสร้างคุณลักษณะที่คุณต้องการโดยไม่ต้องพึ่งพาอาศัยกันจำนวนมากหรือเขียนโค้ดการค้นหาซ้ำๆ ด้วยตัวเอง

การค้นหาด้วยขอบเขต

ลองนึกภาพ #index วิธีบนตัวควบคุม RESTful ของคุณที่แสดงตารางผลิตภัณฑ์ ผลิตภัณฑ์อาจใช้งานอยู่ รอดำเนินการ หรือไม่ใช้งาน มีอยู่ในที่เดียวและมีชื่อ

หากคุณต้องการกรองผลิตภัณฑ์เหล่านี้ คุณสามารถเขียนขอบเขตบางส่วน:

app/models/product.rb
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'

ผู้ควบคุมสามารถใช้ขอบเขตเหล่านี้เพื่อกรองผลลัพธ์ของคุณ:

app/controllers/product_controller.rb
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

แน่นอนว่าต้องมีการล้างข้อมูล

คุณสามารถดูว่ารหัสนี้เริ่มเทอะทะและซ้ำซากได้อย่างไร! แน่นอนว่าคุณกำลังใช้ Ruby อยู่ ดังนั้นคุณจึงสามารถวนซ้ำได้:

app/controllers/product_controller.rb
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

โซลูชันที่นำกลับมาใช้ใหม่ได้

คุณสามารถย้ายโค้ดนี้ไปยังโมดูลและรวมไว้ในโมเดลใดๆ ที่สนับสนุนการกรอง:

app/models/concerns/filterable.rb
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
app/models/product.rb
class Product
  include Filterable
  ...
end
app/controllers/product_controller.rb
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 ดังนั้น หากคุณใช้ params เพื่อกำหนดลำดับการจัดเรียง คุณควร เสมอ ตรวจสอบชื่อคอลัมน์ที่ผู้ใช้ของคุณส่งถึงคุณ และอนุญาตเฉพาะค่าที่คุณรู้ว่าปลอดภัย

ไซต์ Rails SQL Injection จะช่วยให้คุณเรียนรู้ว่าวิธี ActiveRecord ใดมีช่องโหว่ คุณจึงสามารถรักษาแอปของคุณให้ปลอดภัยได้

คุณเรียนรู้ได้ดีขึ้นด้วยวิดีโอไหม

คุณสามารถดูทุกขั้นตอน ตั้งแต่เริ่มต้นแอปใหม่ไปจนถึงเพิ่มการค้นหาและการกรองใน screencast ที่แสดงร่วม เราจะสร้างแอป กรอกข้อมูลตัวอย่าง เพิ่มแบบฟอร์มค้นหา และเชื่อมต่อ และคุณจะได้รับแหล่งที่มาพร้อมกับวิดีโอ เพื่อให้คุณสามารถอ้างอิงกลับเมื่อคุณเพิ่มการค้นหาและการกรองแบบง่ายๆ ลงในแอป Rails ของคุณเอง

เรียนรู้เพิ่มเติมเกี่ยวกับ screencast ที่นี่!