假设我有Book模型和作者模型。我想列出按书籍数量排序的所有作者。最好的方法是什么?
我知道如何在SQL中执行此操作,方法是使用嵌套选择或使用某些连接执行。但我想知道的是如何很好地使用ActiveRecord。
答案 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调用。