2009-06-05 42 views
6

比方說,我有書籍模型和作者模型。我想列出按書目數排序的所有作者。什麼是最好的方式來做到這一點?如何使用ActiveRecord對作者的書數進行排序?

我知道如何在SQL中做到這一點,無論是通過在哪裏..在嵌套選擇或與一些連接。但是我想知道的是如何用ActiveRecord很好地做到這一點。

回答

9

視爲凱文曾建議,counter_cache是​​最簡單的選擇,我會用什麼肯定。

class Author < ActiveRecord::Base 
    has_many :books, :counter_cache => true 
end 

class Book < ActiveRecord::Base 
    belongs_to :author 
end 

如果你正在使用Rails 2.3,你想這是默認的排序,你可以使用新的default_scope方法:

class Author < ActiveRecord::Base 
    has_many :books, :counter_cache => true 

    default_scope :order => "books_count DESC" 
end 

books_count是執行反緩存行爲領域,並且有可能比直接在默認範圍內使用它更好,但它會給你提供想法並完成工作。

編輯:

在迴應評論,詢問如果非Rails應用程序改變了數據,那麼它可以,但不是在默認方式爲Rails的增量和保存時間遞減計數器counter_cache會工作。你可以做的是在after_save回調中編寫你自己的實現。

class Author < ActiveRecord::Base 
    has_many :books 

    after_save :update_counter_cache 

    private 
    def update_counter_cache 
     update_attribute(:books_count, self.books.length) unless self.books.length == self.books_count 
    end 
end 

現在你沒有安裝counter_cache,但如果你的名字在數據庫books_count現場爲每counter_cache慣例然後當你擡頭:

@Author = Author.find(1) 
puts @author.books.size 

它仍然使用計數器緩存號碼而不是執行數據庫查找。當然,這隻會在rails應用程序更新表時才起作用,所以如果另一個應用程序執行某些操作,那麼在rails應用程序返回並保存之前,您的數字可能會不同步。解決這個問題的唯一方法就是我可以想到的是,如果你的Rails應用程序沒有經常查找足夠的東西以使其無關緊要,那麼就可以同步數字。

+0

會執行計數器緩存工作嗎? – dplante 2009-06-07 04:45:39

7

我建議將計數器緩存作爲作者的另一個屬性(Rails通過關聯選項支持此屬性)。這是迄今爲止最快的方法,Rails在確保計數保持同步方面相當不錯。

+2

感謝您的快速和準確的答案。我用你的答案搜索更多的信息,並找到http://railscasts.com/episodes/23-counter-cache-column,這也非常有用。我選擇了railsninja的答案,因爲它更全面,並且可以更好地幫助路過人。 – 2009-06-06 00:31:04

9

http://www.ruby-forum.com/topic/164155

Book.find(:all, :select => "author_id, count(id) as book_count", :group => "author_id", :order => "book_count") 
+0

對。這基本上只是做一個SQL查詢並讓DBMS來完成這項工作,這是最簡單也是最好的方法。特別是,您希望這樣做是爲了避免在一個查詢執行您所需的操作時執行多次查詢(可能多達每位作者一個查詢)。如果非rails應用程序直接更新數據庫中的數據(即刪除書籍), – 2009-06-06 08:24:15

3

假設軌道3

@authors=Authors.include(:books).sort do |a,b| 
    a.books.size <=> b.books.size 
end 

注意:這將返回記錄的數組,而不是一個ActiveRecord:關係。注意2:使用大小,不計數,因爲count會執行對數據庫的sql調用。

相關問題