บทความนี้มีในภาษาเกาหลีด้วย ขอบคุณ Soonsang Hong!
ขอบเขตเป็นวิธีที่ยอดเยี่ยมในการดึงวัตถุที่ถูกต้องออกจากฐานข้อมูลของคุณ:
class Review < ActiveRecord::Base
scope :most_recent, -> (limit) { order("created_at desc").limit(limit) }
end
คุณจะใช้ขอบเขตดังนี้:
@recent_reviews = Review.most_recent(5)
การเรียกขอบเขตนั้นดู ตรง เหมือนเรียก class method ใน Review
. และง่ายต่อการสร้างเป็นวิธีการของชั้นเรียนแทน:
def self.most_recent(limit)
order("created_at desc").limit(limit)
end
@recent_reviews = Review.most_recent(5)
แล้วทำไมคุณถึงใช้ขอบเขตในเมื่อคุณสามารถใช้วิธีคลาส Ruby ปกติได้ มันคุ้มค่าไหมที่จะแยกแนวคิดเหล่านี้ออกจากกันโดยสิ้นเชิง แต่เทียบเท่ากับแนวคิดในหัวของคุณ? เกิดอะไรขึ้นถ้าคุณพบข้อบกพร่องแปลก ๆ สิ่งพิเศษทั้งหมดนี้เป็นสิ่งที่ทำให้ Rails เรียนรู้ได้ยากขึ้นใช่หรือไม่
เมื่อ จะ ควรใช้ขอบเขตแทนวิธีการเรียนหรือไม่
เหตุใดจึงต้องใช้ขอบเขตในเมื่อเรามีเมธอดของคลาสอยู่แล้ว
จะเป็นอย่างไรถ้าคุณต้องการคว้าบทวิจารณ์ทั้งหมดที่เขียนขึ้นหลังจากวันที่ระบุ แต่ถ้าไม่ได้ระบุวันที่ คุณต้องการ ทั้งหมด ความคิดเห็นกลับมาแทน?
ขอบเขตจะมีลักษณะดังนี้:
scope :created_since, ->(time) { where("reviews.created_at > ?", time) if time.present? }
ง่ายพอใช่มั้ย? แล้ววิธีการเรียนล่ะ
def self.created_since(time)
if time.present?
where("reviews.created_at > ?", time)
else
all
end
end
ต้องใช้การทำงานพิเศษเล็กน้อย ขอบเขตต้องการส่งคืนขอบเขต ดังนั้นจึงเชื่อมโยงเข้าด้วยกันได้ง่าย:
Review.positive.created_since(5.days.ago)
แต่เพื่อให้วิธีการเรียนทำงานในลักษณะเดียวกัน คุณต้องจัดการกรณีที่เวลาเป็นศูนย์โดยเฉพาะ มิฉะนั้น ผู้โทร จะต้องค้นหาว่ามีขอบเขตที่ถูกต้องและเชื่อมโยงได้
วิธีการที่ส่งคืนวัตถุประเภทเดียวกันเสมอนั้นมีประโยชน์จริงๆ . คุณไม่ต้องกังวลกับเคสขอบหรือข้อผิดพลาดมากนัก คุณสามารถสมมติได้ว่าคุณจะได้รับสิ่งของที่สามารถใช้ได้คืนเสมอ
ในที่นี้หมายความว่าคุณสามารถเชื่อมโยงขอบเขตเข้าด้วยกันโดยไม่ต้องกังวลว่า nil
คุณค่ากลับมา
ยังมีวิธีที่คุณสามารถทำลายสมมติฐานที่ว่าคุณจะได้ขอบเขตกลับมาเสมอ:
scope :broken, -> { "Hello!!!" }
irb(main):001:0> Review.broken.most_recent(5)
NoMethodError: undefined method `most_recent' for "Hello!!!":String
แต่ฉันไม่เคยมีสิ่งนั้นเกิดขึ้นในโค้ดจริง
สิ่งที่ฉันชอบมากที่สุดเกี่ยวกับขอบเขตคือมันแสดงความตั้งใจ . คุณกำลังบอกคนต่อไปที่อ่านโค้ดของคุณว่า "วิธีนี้สามารถผูกมัดได้ ในที่สุดจะกลายเป็นรายการของวัตถุ และจะช่วยคุณเลือกชุดของวัตถุที่เหมาะสม" นั่นเป็นมากกว่าวิธีการเรียนทั่วไปทั้งหมด
เมื่อใดที่คุณควรใช้วิธีคลาสแทนขอบเขต
เนื่องจากขอบเขตแสดงเจตจำนง ฉันจึงใช้ขอบเขตเหล่านี้ทุกครั้งที่ผูกมัดขอบเขตที่เรียบง่ายและมีอยู่ในตัว (เช่น where
และ limit
) ในขอบเขตที่ซับซ้อนยิ่งขึ้น . การค้นหากลุ่มวัตถุที่เหมาะสมคือสิ่งที่กำหนดขอบเขตไว้
มีข้อยกเว้นสองประการ:
- เมื่อฉันต้องการโหลดขอบเขตล่วงหน้า ฉันจะเปลี่ยนเป็นการเชื่อมโยงแทน .
- เมื่อฉันทำมากกว่าการโยงขอบเขตในตัวไปยังขอบเขตที่ใหญ่ขึ้น ฉันใช้เมธอดของคลาส .
เมื่อลอจิกขอบเขตของคุณมีความซับซ้อน วิธีการเรียนจะรู้สึกเหมือนเป็นสถานที่ที่เหมาะสม
ภายในวิธีการเรียน คุณสามารถผสมรหัส Ruby กับรหัสฐานข้อมูลได้อย่างง่ายดาย หากคุณมีรหัสการจัดเรียงที่เขียนใน Ruby ได้ง่ายกว่า คุณสามารถคว้าอ็อบเจ็กต์ของคุณในลำดับเริ่มต้น และใช้ sort_by เพื่อจัดลำดับให้ถูกต้อง
หรือหากคุณรู้สึกยุ่งยากเป็นพิเศษ วิธีการของคลาสสามารถดึงข้อมูลจากที่ต่างๆ ได้ เช่น ฐานข้อมูลของคุณ Redis หรือ API หรือบริการภายนอก จากนั้นจึงนำมารวมกันเป็นคอลเลกชั่นของวัตถุที่ รู้สึก เหมือนขอบเขตที่ถูกเปลี่ยนเป็นอาร์เรย์
ถึงอย่างนั้น ก็ยังดีที่จะใส่การเลือก การจัดเรียง การเข้าร่วม และการกรองโค้ดไว้ในขอบเขต จากนั้น ใช้ขอบเขตของคุณภายในวิธีการเรียนของคุณ คุณจะลงเอยด้วยวิธีการเรียนที่ชัดเจนขึ้นและขอบเขตที่คุณใช้ได้ทั่วทั้งแอป
ขอบเขตเป็นหนึ่งในคุณสมบัติ Rails ที่ฉันโปรดปราน คุณสามารถทำสิ่งที่ทรงพลังได้ อ่านบทความของฉันเกี่ยวกับการจัดเรียงและกรองโมเดล Rails เพื่อดูตัวอย่างขอบเขตที่มีประโยชน์อย่างยิ่ง
และมีวิธีง่ายๆ ในการควบคุมขอบเขตด้วยการใช้ขอบเขต:เล่นกับมันภายในแอปขนาดเล็กที่เน้น บทตัวอย่างฟรีของ Practicing Rails จะแสดงให้คุณเห็นวิธีการ ลองดูสิ!