Thứ tự sắp xếp mặc định cho một mô hình đường ray?


255

Tôi muốn chỉ định một thứ tự sắp xếp mặc định trong mô hình của tôi.

Vì vậy, khi tôi làm .where()mà không chỉ định, .order()nó sử dụng sắp xếp mặc định. Nhưng nếu tôi chỉ định một .order(), nó sẽ ghi đè mặc định.

Câu trả lời:


544

default_scope

Điều này hoạt động cho Rails 4+:

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

Đối với Rails 2.3, 3, bạn cần điều này thay thế:

default_scope order('created_at DESC')

Đối với đường ray 2.x:

default_scope :order => 'created_at DESC'

Trường created_atbạn muốn sắp xếp mặc định được thực hiện ở đâu.

Lưu ý: ASC là mã để sử dụng cho Tăng dần và DESC là giảm dần ( desc, KHÔNG dsc !).

scope

Khi bạn đã quen với điều đó, bạn cũng có thể sử dụng scope:

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

Đối với Rails 2 bạn cần named_scope.

:publishedphạm vi cung cấp cho bạn Book.publishedthay vì Book.find(:published => true).

Vì Rails 3, bạn có thể 'xâu chuỗi' các phương thức đó lại với nhau bằng cách nối chúng với các khoảng thời gian giữa chúng, do đó, với các phạm vi trên, giờ đây bạn có thể sử dụng Book.published.confirmed.

Với phương pháp này, truy vấn không thực sự được thực hiện cho đến khi cần kết quả thực tế (đánh giá lười biếng), do đó, 7 phạm vi có thể được kết nối với nhau nhưng chỉ dẫn đến 1 truy vấn cơ sở dữ liệu thực tế, để tránh các vấn đề về hiệu năng khi thực hiện 7 truy vấn riêng biệt.

Bạn có thể sử dụng một tham số được truyền vào như ngày hoặc user_id (thứ gì đó sẽ thay đổi vào thời gian chạy và do đó sẽ cần 'đánh giá lười biếng', với lambda, như thế này:

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

Cuối cùng, bạn có thể tắt phạm vi mặc định với:

Book.with_exclusive_scope { find(:all) } 

hoặc thậm chí tốt hơn:

Book.unscoped.all

sẽ vô hiệu hóa bất kỳ bộ lọc (điều kiện) hoặc sắp xếp (thứ tự theo).

Lưu ý rằng phiên bản đầu tiên hoạt động trong Rails2 + trong khi phiên bản thứ hai (không có tỷ lệ) chỉ dành cho Rails3 +


Vì vậy, ... nếu bạn đang nghĩ, hmm, vậy thì đây cũng giống như các phương thức thì ..., yup, đó chính xác là những phạm vi này!
Chúng giống như có def self.method_name ...code... endnhưng như mọi khi với ruby, chúng là những phím tắt cú pháp nhỏ (hay 'đường') để làm mọi thứ dễ dàng hơn cho bạn!

Trong thực tế, chúng là các phương thức cấp Lớp khi chúng hoạt động trên 1 bộ hồ sơ 'tất cả'.

Tuy nhiên, định dạng của chúng đang thay đổi, với đường ray 4 có cảnh báo không dùng nữa khi sử dụng #scope mà không truyền đối tượng có thể gọi được. Ví dụ: phạm vi: đỏ, trong đó (màu: 'đỏ') nên được thay đổi thànhscope :red, -> { where(color: 'red') } .

Là một lưu ý phụ, khi được sử dụng không chính xác, _scope mặc định có thể bị lạm dụng / lạm dụng.
Điều này chủ yếu là khi nó được sử dụng cho các hành động như wheregiới hạn (lọc) lựa chọn mặc định (một ý tưởng tồi cho mặc định) thay vì chỉ được sử dụng để đặt hàng kết quả.
Đối với các wherelựa chọn, chỉ cần sử dụng phạm vi được đặt tên thông thường. và thêm phạm vi mà vào trong truy vấn, ví dụ như Book.all.publishednơi publishedlà một phạm vi được đặt tên.

Tóm lại, phạm vi thực sự tuyệt vời và giúp bạn đẩy mọi thứ vào mô hình cho phương pháp DRYer của bộ điều khiển mô hình béo '.


1
Vui lòng xem xét cảnh báo Dave Thomas' về việc sử dụng default_scope trước khi sử dụng nó như được mô tả trong bài viết này: pragdave.blogs.pragprog.com/pragdave/2012/03/...
Reto

3
nó sẽ không an toàn hơn để làm gì default_scope { order("#{table_name}.created_at DESC") }?
cyrilchampier

37
Đường ray 4:default_scope { order(created_at: :desc) }
Marcus

2
Ít nhất 4.2.6dường như sắp xếp theo updated_atkhông created_at.
Ain Tohvri

2
@AinTohvri nói đúng. Điều này chỉ khiến tôi bất ngờ trong Rails 4.2. Tại sao sắp xếp updated_attheo mặc định? : - |
Sixty4bit

112

Một bản cập nhật nhanh chóng cho câu trả lời tuyệt vời của Michael ở trên.

Đối với Rails 4.0+, bạn cần đặt sắp xếp của mình vào một khối như thế này:

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

Lưu ý rằng câu lệnh được đặt trong một khối được biểu thị bằng dấu ngoặc nhọn.

Họ đã thay đổi nó vì nó quá dễ dàng để vượt qua trong một cái gì đó năng động (như thời điểm hiện tại). Điều này loại bỏ vấn đề vì khối được đánh giá trong thời gian chạy. Nếu bạn không sử dụng một khối, bạn sẽ gặp lỗi này:

Hỗ trợ gọi #default_scope mà không bị chặn. Ví dụ thay vì default_scope where(color: 'red'), vui lòng sử dụngdefault_scope { where(color: 'red') } . (Ngoài ra, bạn chỉ có thể xác định lại self.default_scope.)

Như @Dan đề cập trong bình luận của anh ấy bên dưới, bạn có thể thực hiện cú pháp rubyish như thế này:

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

hoặc có nhiều cột:

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

Cảm ơn @Dan !


28
Trong rails 4, điều này cũng có thể được viết như default_scope { order(created_at: :desc) }thể, giống như tôi, bạn cố gắng giảm thiểu cú pháp sql trong rails. <br/> Nếu bạn có nhiều cột để đặt hàng và bạn muốn sử dụng cú pháp mới, bạn có thể cần phải bọc desc các cột trong ria mép như thế nàydefault_scope { order({begin_date: :desc}, :name) }
Dan

1
@Dan - Nhận xét của bạn không chỉ loại bỏ SQL, đây còn là một cú pháp Rubyish hơn.
B Bảy ngày

6

Bạn có thể sử dụng default_scope để triển khai thứ tự sắp xếp mặc định http://api.rubyonrails.org/groupes/ActiveRecord/Scoping/Default/ClassMethods.html


6
Các liên kết được làm việc nhưng không có gì về là default_scopetrên trang đó, vì nó đã được refactored từ ActiveRecord::Basevào ActiveRecord::Scoping::Default::ClassMethods( api.rubyonrails.org/classes/ActiveRecord/Scoping/Default/... )
Daniel Rikowski
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.