Scope ใน Rails คืออะไร และทำไมถึงมีประโยชน์?
Scope คือคำสั่งสืบค้น (custom queries) ที่คุณกำหนดไว้ภายในโมเดลของ Rails โดยใช้เมธอด scope
ทุก Scope รับอาร์กิวเมนต์ 2 ค่า:
- ชื่อ (name) — ใช้เรียก Scope นี้ในโค้ดของคุณ
- ลัมบ์ดา (lambda) — ใช้สร้างคำสั่งสืบค้น
รูปแบบจะเป็นแบบนี้:
class Fruit < ApplicationRecord
scope :with_juice, -> { where("juice > 0") }
end
เมื่อเรียกใช้ Scope คุณจะได้ออบเจ็กต์ ActiveRecord::Relation กลับมา
ซึ่งหมายความว่าคุณสามารถ เชื่อมต่อ (chain) และรวม (combine) Scopes ได้!
ตัวอย่าง:
Fruit.with_juice.with_round_shape.first(3)
ควรใช้ Scopes เมื่อไหร่?
Scopes ดีนะ แต่เราควรใช้เมื่อไหร่? มาดูตัวอย่างกัน
def index
@books = Book.where("LENGTH(title) > 20")
end
นี่คือ Action index ใน Controller ที่ต้องการแสดงหนังสือที่ชื่อยาวกว่า 20 ตัวอักษร
เขียนแบบนี้ก็ได้ แต่ถ้าคุณต้องการใช้ Query นี้ในหลายที่ โค้ดก็จะซ้ำซ้อน
โค้ดซ้ำทำให้โปรเจกต์ยากต่อการบำรุงรักษา
มาเลื่อน Query นี้ไปใส่ใน Scope แทนกันเถอะ
เขียนแบบนี้:
class Book
scope :with_long_title, -> { where("LENGTH(title) > 20") }
end
ตอนนี้ Controller Action จะกลายเป็น:
def index @books = Book.with_long_title end
สะอาดขึ้นเยอะ!
วิธีใช้ Rails Scopes พร้อมอาร์กิวเมนต์
คุณอาจอยากส่งค่าตัวแปรเข้าไปใน Scope เพื่อให้ยืดหยุ่นขึ้น
ทำได้แบบนี้:
class Book
scope :with_long_title, ->(length) { where("LENGTH(title) > ?", length) }
end
เครื่องหมายคำถาม (?) เป็น placeholder จะถูกแทนที่ด้วยค่าของ length ทำให้โค้ดปลอดภัยขึ้น
ถ้าอยากให้มีค่าเริ่มต้น (default value):
class Book
scope :with_long_title, ->(length = 20) { where("LENGTH(title) > ?", length) }
end
ลองใช้ดูสิ!
Scope vs Class Method
Scopes ไม่ได้ทำอะไรลึกลับหรือพิเศษเลย — มันก็คือเมธอดธรรมดา
จริงๆ แล้ว คุณทำได้เหมือนกันด้วย Class Method:
เช่นนี้:
class Fruit
def self.with_juice
where("juice > 0")
end
end
แต่ Scopes มีข้อดีด้านการออกแบบ:
- โค้ดสะอาดกว่า เพราะ Syntax เฉพาะเจาะจง
- Scopes ใช้ทำอย่างเดียว — ดูชื่อก็รู้ว่าเป็น Query scope
- ไม่ได้ปนกับเมธอดอื่น ๆ ทำให้หาง่าย
ทางด้านฟังก์ชัน: ต่างกันตรงที่ Scope รับประกันว่าจะคืน ActiveRecord::Relation เสมอ ส่วน Class Method ไม่รับประกัน — ช่วยป้องกัน Error ตอน Scope คืนค่าเป็น nil
อย่าใช้ Default Scopes
Default Scope คือ Scope ที่ถูกนำไปใช้กับโมเดลโดยอัตโนมัติ
ตัวอย่าง:
class Post
default_scope { where(published: true) }
end
ดูน่าสนใจใช่ไหม? แต่จริงๆ แล้วมันมักเป็นตัวเลือกที่ผิด เพราะคุณมักจะลืมว่ามันอยู่ ทำให้เกิด Bug แปลกๆ และเสียเวลา Debug มาก
ที่ว่านั้น...
ถ้าคุณบังคับต้องทำงานกับ Default Scope อาจต้องใช้เมธอด unscoped เพื่อปิด Scope ทั้งหมดที่กำลังทำงานอยู่
สรุป
เยี่ยมมาก! จากบทความนี้คุณเรียนรู้วิธีใช้ Rails Scopes อย่างมีประสิทธิภาพแล้ว
อย่าลืมนำไปปฏิบัติจริงเพื่อให้จดจำได้นานขึ้น
ขอบคุณที่อ่านครับ 🙂