ลำดับการจัดเรียงเริ่มต้นสำหรับรุ่นราง?


255

ฉันต้องการระบุลำดับการจัดเรียงเริ่มต้นในโมเดลของฉัน

ดังนั้นเมื่อฉันทำ.where()โดยไม่ระบุ.order()มันใช้การเรียงลำดับเริ่มต้น แต่ถ้าฉันระบุ.order()มันมันจะแทนที่ค่าเริ่มต้น

คำตอบ:


544

default_scope

ใช้งานได้กับ Rails 4+:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

สำหรับ Rails 2.3, 3 คุณต้องการสิ่งนี้แทน:

default_scope order('created_at DESC')

สำหรับ Rails 2.x:

default_scope :order => 'created_at DESC'

ไหนcreated_atเป็นเขตที่คุณต้องการเริ่มต้นการเรียงลำดับที่จะต้องทำใน

หมายเหตุ: ASCเป็นรหัสที่จะใช้สำหรับ Ascending แยกและDESCสำหรับลงมา ( desc, ไม่ได้ dsc !)

scope

เมื่อคุณคุ้นเคยกับสิ่งนั้นแล้วคุณยังสามารถใช้scope:

class Book < ActiveRecord::Base
  scope :confirmed, :conditions => { :confirmed => true }
  scope :published, :conditions => { :published => true }
end

สำหรับทางรถไฟ 2 named_scopeที่คุณต้องการ

:publishedขอบเขตช่วยให้คุณแทน Book.published Book.find(:published => true)

ตั้งแต่ Rails 3 คุณสามารถ 'เชื่อมโยง' วิธีการเหล่านั้นเข้าด้วยกันด้วยการเชื่อมต่อมันเข้ากับช่วงเวลาระหว่างพวกเขาดังนั้นด้วยขอบเขตด้านบนคุณสามารถใช้งานBook.published.confirmedได้แล้ว

ด้วยวิธีนี้แบบสอบถามจะไม่ถูกดำเนินการจริง ๆ จนกว่าจะต้องการผลลัพธ์ที่แท้จริง (การประเมินแบบสันหลังยาว) ดังนั้นขอบเขต 7 รายการจึงสามารถถูกโยงเข้าด้วยกัน แต่ส่งผลให้เกิด 1 แบบสอบถามฐานข้อมูลจริงเท่านั้นเพื่อหลีกเลี่ยงปัญหาประสิทธิภาพการทำงาน

คุณสามารถใช้พารามิเตอร์ส่งผ่านเช่นวันที่หรือ user_id (สิ่งที่จะเปลี่ยนแปลงในเวลาทำงานและจะต้องมี 'การประเมินผลที่ขี้เกียจ' กับแลมบ์ดาเช่นนี้:

scope :recent_books, lambda 
  { |since_when| where("created_at >= ?", since_when) }
  # Note the `where` is making use of AREL syntax added in Rails 3.

ในที่สุดคุณสามารถปิดใช้งานขอบเขตเริ่มต้นด้วย:

Book.with_exclusive_scope { find(:all) } 

หรือดีกว่า:

Book.unscoped.all

ซึ่งจะปิดการใช้งานตัวกรอง (เงื่อนไข) หรือเรียงลำดับ (เรียงตาม)

โปรดทราบว่ารุ่นแรกทำงานใน Rails2 + ในขณะที่รุ่นที่สอง (ไม่ระบุขนาด) ใช้สำหรับ Rails3 + เท่านั้น


ดังนั้น ... ถ้าคุณกำลังคิดอืมดังนั้นนี่ก็เป็นวิธีการเหมือนกัน ... , ใช่นั่นคือสิ่งที่ขอบเขตเหล่านี้!
พวกเขาเป็นเหมือนมีdef self.method_name ...code... endแต่กับทับทิมเสมอพวกเขามีทางลัด syntax (หรือ 'น้ำตาล') เพื่อให้ทุกอย่างง่ายขึ้นสำหรับคุณ!

ในความเป็นจริงพวกเขาเป็นวิธีการเรียนระดับที่พวกเขาทำงานใน 1 ชุดของระเบียน 'ทั้งหมด'

รูปแบบของพวกเขากำลังเปลี่ยนแปลงอย่างไรก็ตามด้วย Rails 4 จะมีคำเตือนการคัดค้านเมื่อใช้ #scope โดยไม่ผ่านวัตถุที่เรียกได้ ยกตัวอย่างเช่นขอบเขต: สีแดง, ที่ (สี: 'red') scope :red, -> { where(color: 'red') }ควรจะเปลี่ยนไป

ในฐานะที่เป็นบันทึกด้านข้างเมื่อใช้อย่างไม่ถูกต้อง_scope ที่เป็นค่าเริ่มต้นอาจถูกนำไปใช้ในทางที่ผิด / ถูกใช้ในทางที่ผิด
นี่เป็นเรื่องเกี่ยวกับเวลาที่มันถูกใช้สำหรับการกระทำเช่นwhereการ จำกัด (การกรอง) การเลือกเริ่มต้น ( ความคิดที่ไม่ดีสำหรับการเริ่มต้น) แทนที่จะใช้เพื่อการสั่งซื้อผลลัพธ์เท่านั้น
สำหรับการwhereเลือกเพียงใช้ขอบเขตปกติที่มีชื่อ และเพิ่มขอบเขตนั้นในแบบสอบถามเช่นBook.all.publishedที่ไหนpublishedเป็นขอบเขตที่มีชื่อ

สรุปแล้วขอบเขตนั้นยอดเยี่ยมมากและช่วยให้คุณผลักดันสิ่งต่างๆเข้าสู่โมเดลสำหรับแนวทาง DRYer 'fat model thin'


1
โปรดพิจารณาคำเตือนของ Dave Thomas เกี่ยวกับการใช้ default_scope ก่อนที่จะใช้ดังที่อธิบายไว้ในโพสต์นี้: pragdave.blogs.pragprog.com/pragdave/2012/03/…
reto

3
มันจะปลอดภัยกว่าdefault_scope { order("#{table_name}.created_at DESC") }ไหมถ้าจะทำ?
cyrilchampier

37
Rails 4:default_scope { order(created_at: :desc) }
Marcus

2
อย่างน้อยที่สุดก็4.2.6ดูเหมือนว่าจะเรียงลำดับตามไม่ได้updated_at created_at
Ain Tohvri

2
@AinTohvri ถูกต้อง นี่ทำให้ฉันประหลาดใจใน Rails 4.2 ทำไมต้องจัดเรียงupdated_atตามค่าเริ่มต้น? : - |
sixty4bit

112

การอัปเดตอย่างรวดเร็วสำหรับคำตอบที่ยอดเยี่ยมของ Michael ด้านบน

สำหรับ Rails 4.0+ คุณจะต้องเรียงลำดับของคุณในบล็อกดังนี้:

class Book < ActiveRecord::Base
  default_scope { order('created_at DESC') }
end

ขอให้สังเกตว่าคำสั่งคำสั่งจะถูกวางไว้ในบล็อกที่แสดงโดยวงเล็บปีกกา

พวกเขาเปลี่ยนมันเพราะมันง่ายเกินกว่าที่จะผ่านไปในสิ่งที่มีพลัง (เช่นเวลาปัจจุบัน) สิ่งนี้จะลบปัญหาเนื่องจากบล็อกถูกประเมินที่รันไทม์ หากคุณไม่ใช้บล็อกคุณจะได้รับข้อผิดพลาดนี้:

การสนับสนุนสำหรับการโทร #default_scope ที่ไม่มีบล็อกถูกลบออก ตัวอย่างเช่นแทนที่จะกรุณาใช้default_scope where(color: 'red') default_scope { where(color: 'red') }(อีกทางหนึ่งคุณสามารถกำหนด self.default_scope ใหม่ได้)

ตามที่@Danกล่าวถึงในความคิดเห็นของเขาด้านล่างคุณสามารถทำไวยากรณ์ rubyish เพิ่มเติมเช่นนี้:

class Book < ActiveRecord::Base
  default_scope { order(created_at: :desc) }
end

หรือมีหลายคอลัมน์:

class Book < ActiveRecord::Base
  default_scope { order({begin_date: :desc}, :name) }
end

ขอบคุณ@ แดน !


28
ใน Rails 4 สิ่งนี้สามารถเขียนdefault_scope { order(created_at: :desc) }ได้เหมือนเช่นฉันคุณพยายามลดไวยากรณ์ของ sql ในรางให้น้อย <br/> หากคุณมีหลายคอลัมน์ที่จะเรียงตามและคุณต้องการใช้ไวยากรณ์ใหม่ คอลัมน์ในหนวดแบบนี้default_scope { order({begin_date: :desc}, :name) }
Dan

1
@Dan - ความคิดเห็นของคุณไม่เพียง แต่กำจัด SQL เท่านั้น แต่ยังเป็นไวยากรณ์ของ Rubyish อีกด้วย
B เซเว่น

6

คุณสามารถใช้ default_scope เพื่อใช้การเรียงลำดับเริ่มต้นได้ที่ http://api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/ClassMethods.html


6
การเชื่อมโยงคือการทำงาน แต่มีอะไรเกี่ยวกับdefault_scopeในหน้านั้นเพราะได้รับการ refactored จากActiveRecord::Baseเข้าActiveRecord::Scoping::Default::ClassMethods( api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/... )
แดเนียล Rikowski
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.