2010-10-29 21 views
26

Trước đây tôi ra lệnh cho bài viết của tôi như thế này:Làm thế nào để bạn đặt hàng theo phương pháp mô hình tùy chỉnh không có thuộc tính trong SQL?

@posts = Post.find(:all, :order => "created_at DESC") 

Nhưng bây giờ tôi muốn thay thế created_at với một phương pháp tùy chỉnh tôi đã viết trong mô hình bài đó đưa ra một số kết quả của nó.

Tôi đoán:

@posts = Post.find(:all, :order => "custom_method DESC") 

mà thất bại ..

Trả lời

30

Nó thất bại bởi vì bạn đang yêu cầu db của bạn để làm việc phân loại.

@posts = Post.all.sort {|a,b| a.custom_method <=> b.custom_method}

Lưu ý rằng điều này trở nên không tầm thường khi bạn muốn bắt đầu kết quả phân trang và không còn muốn lấy .all. Hãy suy nghĩ về thiết kế của bạn một chút trước khi bạn đi với điều này.

+26

Hoặc đơn giản hơn bạn có thể sử dụng Post.all.sort_by (&: custom_method), đạt được kết quả tương tự nhưng hơi dễ dàng hơn trên mắt. – NZKoz

+0

Điều này dường như không hoạt động nếu có nils trong trường so sánh của bạn. Có một cách giải quyết cho điều này? Tôi có các giá trị 'display_rank' theo sau [10, 20, 30, nil, nil, nil, nil, nil, nil] câu lệnh này' Event.find (607) .event_staff_users.sort_by {| u | u.display_rank} 'cho lỗi này' ArgumentError: so sánh NilClass với 30 thất bại'. Tôi thấy rằng sử dụng 'event_staff_users.sort_by {| u | u.display_rank hoặc 99999} 'làm việc và đặt nils cuối cùng. sử dụng hoặc 0 sẽ đặt chúng đầu tiên. – Dan

3

Vâng, chỉ Post.find(:all) sẽ trả về một mảng các đối tượng AR. Vì vậy, bạn có thể sử dụng Array.sort_by và vượt qua nó một khối, và kể từ khi những hồ sơ đã được lấy, bạn có thể truy cập vào các thuộc tính ảo bên trong khối mà sort_by mất.

rdoc: Enumerable.sort_by

15

Chỉ cần để mở rộng trên @ câu trả lời Robbie của

Post.all.sort_by {|post| post.custom_method }.reverse 
+0

Hãy cẩn thận nếu có nhiều bài đăng. Bắt tất cả chúng ra khỏi DB và nạp vào các đối tượng ActiveRecord không phải là miễn phí. Khi số lượng bản ghi trở nên lớn, tốc độ chậm sẽ quan trọng đối với một ứng dụng sản xuất. Một trường thực sự trong cơ sở dữ liệu của bạn, với một chỉ mục thích hợp và hạn chế truy vấn đến một tập hợp được phân trang là cách để đi. – jwarchol

+0

Phân trang, được cấp. Nhưng chỉ số thích hợp là không đáng kể bởi vì phương pháp tùy chỉnh của tôi tạo ra thứ hạng dựa trên thời gian. Mà luôn luôn thay đổi. Do đó, kết quả có thể thay đổi ngay lập tức. – Trip

+0

Tôi đã làm việc một chút với các hệ thống xếp hạng. Chúng có thể phức tạp để thực hiện trong thời gian thực cho các bộ hồ sơ lớn khi tính toán không nhỏ. Tốt nhất của may mắn, nếu bạn tìm thấy bất kỳ kỹ thuật hữu ích, xin vui lòng chia sẻ :-) – jwarchol

-5

trong đường ray 3 chúng ta có thể làm được điều này như: Post.order("custom_method DESC")
Khi nâng cấp ứng dụng từ rails2 để rails3

+0

Điều này là không chính xác. – jeffdill2

6

Như câu trả lời đầu tiên ghi nhận, trật tự là một Lệnh Active Record về cơ bản thực hiện truy vấn SQL trên cơ sở dữ liệu của bạn, nhưng trường đó không thực sự tồn tại trong cơ sở dữ liệu của bạn.

Khi ai đó nhận xét, bạn sạch hơn có thể chạy các phương pháp sort_by của Ruby bằng cách sử dụng dấu và (biết thêm here):

Post.all.sort_by(&:custom_method)

Tuy nhiên, mọi việc trở nên phức tạp tùy thuộc vào những gì bạn muốn làm theo quan điểm của bạn. Tôi sẽ chia sẻ một trường hợp gần đây tôi đã làm trong trường hợp đó giúp bạn suy nghĩ thông qua vấn đề của bạn. Tôi cần nhóm tài nguyên của mình bằng một tài nguyên khác gọi là "danh mục", sau đó sắp xếp tài nguyên gốc bằng "netvotes", đó là phương thức mô hình tùy chỉnh, sau đó sắp xếp theo tên. Tôi đã làm điều đó bằng cách:

  • Thứ tự theo tên trong bộ điều khiển: @resources = Resource.order(:name)
  • Phân nhóm theo thể loại trong vòng ngoài của quan điểm: <% @resources.group_by(&:category).each do |category, resources| %>
  • Sau đó sắp xếp các nguồn lực bằng phiếu trong một phần cho nguồn: <%= render resources.sort_by(&:netvotes).reverse %>

Quan điểm là một chút bối rối, vì vậy đây là vòng lặp cái nhìn đầy đủ trong index.html.erb:

<% @resources.group_by(&:category).each do |category, resources| %> 
    <div class="well"> 
    <h3 class="brand-text"><%= category.name %></h3> 
    <%= render resources.sort_by(&:netvotes).reverse %> 
    </div> 
<% end %> 

Và đây là _resource.html.ERB phần:

<div class="row resource"> 
    <div class="col-sm-2 text-center"> 
    <div class="vote-box"> 
     <%= link_to fa_icon('chevron-up lg'), upvote_resource_path(resource), method: :put %><br> 
     <%= resource.netvotes %><br> 
     <%= link_to fa_icon('chevron-down lg'), downvote_resource_path(resource), method: :put %> 
    </div> 
    </div> 
    <div class="col-sm-10"> 
    <%= link_to resource.name, resource.link, target: "_blank" %> 
    <p><%= resource.notes %></p> 
    </div> 
</div> 
2

Đây là một chút phức tạp hơn những gì tôi thích nhưng điều này tôi muốn giữ loại của tôi để ở lại như một mô hình kỷ lục hoạt động để bit của nó phức tạp hơn chỉ

Post.all.sort_by {|post| post.custom_method } 

gì tôi là:

ids = Post.all.sort_by {|post| post.custom_method }.map(&:ids) 
Post.for_ids_with_order(ids) 

đây là một phạm vi tùy chỉnh trong mô hình bài

#app/models/post.rb 
class Post < ApplicationRecord 
    ... 
    scope :for_ids_with_order, ->(ids) { 
    order = sanitize_sql_array(
     ["position(id::text in ?)", ids.join(',')] 
    ) 
    where(:id => ids).order(order) 
    } 

    ... 
end 

Tôi hy vọng rằng điều này giúp đỡ

Các vấn đề liên quan