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

时间:2009-06-05 23:28:05

标签: ruby-on-rails ruby activerecord

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

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

4 个答案:

答案 0 :(得分: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")

答案 1 :(得分:9)

正如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应用程序没有经常查找内容以使其无关紧要,那么就可以同步数字。

答案 2 :(得分:7)

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

答案 3 :(得分:3)

假设有轨道3

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

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

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