ขอบเขต / named_scope ในรางคืออะไร?


106

ฉันเพิ่งเริ่มฝึกงาน นายจ้างของฉันใช้ทับทิมบนรางรถไฟและฉันมักพบไวยากรณ์ใหม่ที่ฉันต้องค้นหาเพื่อทำความเข้าใจ ฉันได้ลองใช้คำอธิบายที่ดีเกี่ยวกับ named_scope แต่สิ่งที่ฉันพบจนถึงตอนนี้ส่วนใหญ่เป็นบล็อกโพสต์ที่ให้การยกย่องเป็นอย่างสูงแทนที่จะเป็นคำจำกัดความหรือคำนำที่ตรงไปตรงมา

ชื่อ _ สโคปคืออะไร (ปัจจุบันเรียกง่ายๆว่าขอบเขต) ในทับทิมบนราง?



2
บล็อกโพสต์นี้มีค่าสำหรับฉันเมื่อเรียนรู้ชื่อขอบเขต: ryandaigle.com/articles/2008/8/20/…
ปีเตอร์บราวน์

1
@notapatch ลิงก์ตายแล้วคุณมีอีกอันไหม
mbigras

Ryan Daigle: ขอบเขตการตั้งชื่อ: ไม่ใช่แค่เงื่อนไขเท่านั้นรู้ไหม: web.archive.org/web/20160306110506/http://…
notapatch

คำตอบ:


213

ขอบเขตคือส่วนย่อยของคอลเล็กชัน ฟังดูซับซ้อน? มันไม่ใช่ ลองนึกภาพสิ่งนี้:

คุณมีผู้ใช้ ตอนนี้ผู้ใช้บางส่วนสมัครรับจดหมายข่าวของคุณ คุณทำเครื่องหมายผู้ที่ได้รับจดหมายข่าวโดยการเพิ่มฟิลด์ลงในฐานข้อมูลผู้ใช้ (user.subscribed_to_newsletter = true) โดยปกติบางครั้งคุณต้องการรับผู้ใช้ที่สมัครรับจดหมายข่าวของคุณ

คุณสามารถทำได้เสมอ:

User.where(subscribed_to_newsletter: true).each do #something

อย่างไรก็ตามแทนที่จะเขียนสิ่งนี้เสมอไปคุณสามารถทำสิ่งนี้ได้

#File: users.rb
class User < ActiveRecord::Base
  scope :newsletter, where(subscribed_to_newsletter: true)
  #yada yada
end

หากคุณใช้Rails 4 หรือใหม่กว่าให้ทำสิ่งนี้แทน:

#File: users.rb
class User < ActiveRecord::Base
  scope :newsletter, -> { where(subscribed_to_newsletter: true) }
  #yada yada
end

สิ่งนี้ช่วยให้คุณสามารถเข้าถึงสมาชิกของคุณได้โดยทำสิ่งนี้:

User.newsletter.each do #something

นี่เป็นตัวอย่างที่ง่ายมาก แต่โดยทั่วไปขอบเขตอาจเป็นเครื่องมือที่มีประสิทธิภาพมากในการทำงานของคุณให้ง่ายขึ้น

ตรวจสอบลิงค์นี้: คำอธิบาย API


7
ฉันจะถามข้อดีของสิ่งนี้ได้ไหมว่าการกำหนดวิธีการในคลาสผู้ใช้ที่เรียกว่า 'subscribedUsers' เช่น 'def self.subscribedUsers self.where (: subscribed_to_newsletter => true) end
redroot

3
@redroot ข้อดีคือscopeไวยากรณ์สะอาดกว่ามากคุณจะได้ผลลัพธ์เหมือนกัน แต่มีเพียงบรรทัดเดียว
Aldo 'xoen' Giambelluca

10
@redroot เคยมีข้อได้เปรียบด้านประสิทธิภาพอย่างมากเนื่องจากขอบเขตจะสืบค้นฐานข้อมูลอย่างเฉื่อยชาในขณะที่วิธีการต่างๆจะทำอย่างกระตือรือร้น ใน Rails 3 เมธอดก็ขี้เกียจเช่นกันดังนั้นตอนนี้ความแตกต่างคือวากยสัมพันธ์มากขึ้น ที่มา
evanrmurphy

ลิงก์เอกสาร API เสียโปรดอัปเดตapi.rubyonrails.org/classes/ActiveRecord/Scoping/Named/…
Lohith MV

ยังอนุญาตให้ใช้ลิงก์
Benjineer

34

ขอบเขตในเรกคอร์ดที่ใช้งานเป็นเหมือนเมธอดคลาส แต่ส่งคืนวัตถุ Relation ซึ่งหมายความว่าคุณสามารถเรียกขอบเขตอื่นหรือวิธีการสืบค้นเรกคอร์ดที่ใช้งานอยู่ได้

ตัวอย่างเช่นหากคุณมีโมเดลซอมบี้ (ตารางซอมบี้) ด้วยวิธีขอบเขตที่กล่าวถึงด้านล่าง

class Zombie
  scope :rotting, -> { where(rotting: true) }
  scope :fresh, -> { where('age < ?', 25) }
  scope :recent, -> { order(created_at: :desc) }
end

และคุณโทร

Zombie.rotting.fresh.recent.limit(3)

แปลเป็น SQL ด้านล่าง

select "zombies.*" from "zombies" where "zombies"."rotting" = 't' and (age<20) order by create_at desc limit 3

ตัวอย่างด้านบนเป็นไปตามไวยากรณ์ของราง 4


ฉันไม่พบตัวอย่างคำสั่ง (: created_at,: desc) ในเอกสารใด ๆ เป็นไปได้ไหมที่คุณหมายถึงscope :recent, -> { order(created_at: :desc) }? apidock.com/rails/v4.2.9/ActiveRecord/QueryMethods/order
notapatch

7

วิธีที่ดีที่สุดในการทำความเข้าใจเกี่ยวกับรายละเอียดคือไปที่เอกสารประกอบ API

คุณจะได้รับรายละเอียดทั้งหมดและวิธีที่เราสามารถใช้ขอบเขต

เอกสาร API ของขอบเขต


7

ขอบเขตเป็นเพียงวิธีการคลาสเท่านั้น

ทำไมต้องใช้?

การกำหนดขอบเขตช่วยให้คุณสามารถระบุคิวรีที่ใช้โดยทั่วไป (ถือได้ว่าเป็นทางลัดสำหรับคิวรีที่ยาวหรือใช้บ่อยที่สุด) ซึ่งสามารถอ้างอิงได้ว่าเป็นการเรียกใช้เมธอดบนอ็อบเจ็กต์หรือโมเดลที่เชื่อมโยงกัน ด้วยขอบเขตเหล่านี้คุณสามารถใช้ทุกวิธีที่ครอบคลุมไว้ก่อนหน้านี้เช่นที่ไหนรวมและรวม วิธีขอบเขตทั้งหมดจะส่งคืนอ็อบเจ็กต์ ActiveRecord :: Relationซึ่งจะอนุญาตให้มีการเรียกใช้เมธอดเพิ่มเติม (เช่นขอบเขตอื่น ๆ )

ในการกำหนดขอบเขตอย่างง่ายเราใช้วิธีการกำหนดขอบเขตภายในคลาสโดยส่งแบบสอบถามที่เราต้องการเรียกใช้เมื่อขอบเขตนี้ถูกเรียก:

class Article < ActiveRecord::Base
  scope :published, -> { where(published: true) }
end

สิ่งนี้เหมือนกับการกำหนดเมธอดคลาสและสิ่งที่คุณใช้เป็นเรื่องของความชอบส่วนบุคคล:

class Article < ActiveRecord::Base
  def self.published
    where(published: true)
  end
end

โปรดไปที่ลิงค์ต่อไปนี้เพื่อดูรายละเอียดทั้งหมดพร้อมตัวอย่าง ฉันหวังว่านี่จะช่วยคุณได้

http://guides.rubyonrails.org/active_record_querying.html


3
มันไม่เหมือนกับการกำหนดวิธีการเรียน วิธีการคลาสจะส่งคืนnilในบางกรณีและไม่สามารถใช้ chainable ได้สำหรับเงื่อนไขบางประการ
Arslan Ali

1
  • ลองนึกภาพคุณมีรูปแบบ: บุคคล

ลองนึกภาพคุณ:

  • ต้องการให้ทุกคนในโลกที่มีผมสีแดง
  • ต้องการให้ทุกคนในโลกที่เล่นคริกเก็ต

คุณสามารถหาคนเหล่านั้นได้โดยใช้ขอบเขต!

Person.red_hair.cricket ## finds all people with red hair who play cricket
Person.red_hair ## finds all people with red hair
Person.cricket ## finds all people who play cricket.

ตอนนี้มันไม่ยากแล้วเหรอ?

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.