如何使用ActiveRecord按作业数量对作者进行排序?

假设我有Book模型和Author模型。 我想列出按书数排序的所有作者。 最好的方法是什么?

我知道如何在SQL中执行此操作,方法是使用嵌套选择或使用某些连接执行。 但我想知道的是如何使用ActiveRecord很好地完成这项工作。

正如Kevin建议的那样,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应用程序改变数据,counter_cache是​​否会起作用,它可以,但不是默认方式,因为Rails会在保存时递增和递减计数器。 你可以做的是在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,但是如果您按照counter_cache约定命名数据库books_count中的字段,那么当您查找时:

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

它仍将使用计数器缓存的数字,而不是执行数据库查找。 当然这仅在rails应用程序更新表时才有效,因此如果另一个应用程序执行了某些操作,那么在rails应用程序返回之前,您的数字可能会不同步,必须保存。 解决这个问题的唯一方法是,如果你的rails应用程序不经常查找事情以使其无关紧要,那么就可以同步数字。

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

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

我建议将计数缓存书计数作为Author的另一个属性(Rails通过关联选项支持此项)。 这是迄今为止最快的方法,Rails非常适合确保它保持计数同步。

假设铁轨3

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

注意:这将返回一个记录数组,而不是ActiveRecord:Relation。

注意2:使用size而不是count,因为count将执行对db的sql调用。