以前我命令我的職位,因爲這:如何通過SQL中沒有屬性的自定義模型方法進行排序?
@posts = Post.find(:all, :order => "created_at DESC")
但現在我想用我的Post模型,給出了一個數字作爲它的結果寫了一個自定義的方法來代替created_at
。
我的猜測:
@posts = Post.find(:all, :order => "custom_method DESC")
它失敗..
以前我命令我的職位,因爲這:如何通過SQL中沒有屬性的自定義模型方法進行排序?
@posts = Post.find(:all, :order => "created_at DESC")
但現在我想用我的Post模型,給出了一個數字作爲它的結果寫了一個自定義的方法來代替created_at
。
我的猜測:
@posts = Post.find(:all, :order => "custom_method DESC")
它失敗..
,因爲你是問你的數據庫來進行排序它失敗。
@posts = Post.all.sort {|a,b| a.custom_method <=> b.custom_method}
注意,當你要開始分頁的結果和不希望再取.all
,這變得不平凡。在你走之前想想你的設計。
那麼,就Post.find(:all)
將返回AR對象的數組。因此,您可以使用Array.sort_by並將其傳遞給一個塊,並且由於這些記錄已被提取,因此您可以訪問sort_by所在塊內的虛擬屬性。
的RDoc:Enumerable.sort_by
只是爲了擴大對@羅比的回答
Post.all.sort_by {|post| post.custom_method }.reverse
要小心,如果有很多職位。將它們全部從數據庫中取出並加載到ActiveRecord對象中並不是免費的。當記錄數量變大時,減速將對生產應用程序至關重要。實際存在於數據庫中的字段,具有適當的索引,並且將查詢限制爲分頁集合是一種方法。 – jwarchol 2010-10-29 21:31:29
分頁,被授予。但適當的索引可以忽略不計,因爲我的自定義方法會根據時間生成排名。哪一個總是在變化。因此結果可以瞬間改變。 – Trip 2010-10-29 21:44:18
我對排名系統工作了一點。當計算不是微不足道的時候,對於大量記錄實時執行可能會非常棘手。祝你好運,如果你發現任何有用的技術,請分享:-) – jwarchol 2010-10-29 22:02:47
我們可以做到這一點是:Post.order("custom_method DESC")
升級時從rails2應用Rails3中
這是不準確的。 – jeffdill2 2015-11-11 18:50:47
作爲第一個答案指出,爲了是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>
這是一個有點比我更喜歡複雜,但這個我喜歡讓我排序保持爲活動記錄模型,以便其位不只是
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
我希望這個幫助
或者稍微簡單一點,你可以使用Post.all.sort_by(&:custom_method),達到相同的結果,但眼睛上稍微容易一些。 – NZKoz 2010-10-29 22:34:15
如果在比較字段中有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