2010-10-29 52 views
26

以前我命令我的職位,因爲這:如何通過SQL中沒有屬性的自定義模型方法進行排序?

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

但現在我想用我的Post模型,給出了一個數字作爲它的結果寫了一個自定義的方法來代替created_at

我的猜測:

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

它失敗..

回答

30

,因爲你是問你的數據庫來進行排序它失敗。

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

注意,當你要開始分頁的結果和不希望再取.all,這變得不平凡。在你走之前想想你的設計。

+26

或者稍微簡單一點,你可以使用Post.all.sort_by(&:custom_method),達到相同的結果,但眼睛上稍微容易一些。 – NZKoz 2010-10-29 22:34:15

+0

如果在比較字段中有nils,這似乎不起作用。有沒有解決這個問題的方法?我有'display_rank'的值[10,20,30,nil,nil,nil,nil,nil,nil]這個語句'Event.find(607).event_staff_users.sort_by {| u | u.display_rank}'給出這個錯誤'ArgumentError:比較NilClass與30失敗'。我發現使用'event_staff_users.sort_by {| u | u.display_rank或99999}工作並將nils放到最後。使用或0會把他們放在第一位。 – Dan 2017-10-26 18:35:43

3

那麼,就Post.find(:all)將返回AR對象的數組。因此,您可以使用Array.sort_by並將其傳遞給一個塊,並且由於這些記錄已被提取,因此您可以訪問sort_by所在塊內的虛擬屬性。

的RDoc:Enumerable.sort_by

15

只是爲了擴大對@羅比的回答

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

要小心,如果有很多職位。將它們全部從數據庫中取出並加載到ActiveRecord對象中並不是免費的。當記錄數量變大時,減速將對生產應用程序至關重要。實際存在於數據庫中的字段,具有適當的索引,並且將查詢限制爲分頁集合是一種方法。 – jwarchol 2010-10-29 21:31:29

+0

分頁,被授予。但適當的索引可以忽略不計,因爲我的自定義方法會根據時間生成排名。哪一個總是在變化。因此結果可以瞬間改變。 – Trip 2010-10-29 21:44:18

+0

我對排名系統工作了一點。當計算不是微不足道的時候,對於大量記錄實時執行可能會非常棘手。祝你好運,如果你發現任何有用的技術,請分享:-) – jwarchol 2010-10-29 22:02:47

-5
在軌道3

我們可以做到這一點是:Post.order("custom_method DESC")
升級時從rails2應用Rails3中

+0

這是不準確的。 – jeffdill2 2015-11-11 18:50:47

6

作爲第一個答案指出,爲了是Active Record命令本質上對數據庫執行SQL查詢,但該字段實際上並不存在於數據庫中。

至於別人的評論,你可以更清晰地使用符號(更多信息here)運行Ruby的方法sort_by:

Post.all.sort_by(&:custom_method)

然而,事情變得複雜取決於你想要做什麼在你看來。我會分享一個我最近做的案例,以幫助您解決問題。我需要通過另一個稱爲「類別」的資源對我的資源進行分組,然後通過「netvotes」(這是一種自定義模型方法)對原始資源進行排序,然後按名稱排序。在控制器

  • 排序方式名稱:@resources = Resource.order(:name)
  • 按類別在視圖中的外環分組:我做到了由<% @resources.group_by(&:category).each do |category, resources| %>
  • 然後通過投票排序的資源在部分資源:<%= render resources.sort_by(&:netvotes).reverse %>

的看法是有點混亂,所以這裏是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 %> 

這裏是_resource.html。ERB部分:

<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

這是一個有點比我更喜歡複雜,但這個我喜歡讓我排序保持爲活動記錄模型,以便其位不只是

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

更復雜的是什麼我做的是:

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

這是中郵模型的自定義範圍

#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 

我希望這個幫助

相關問題