Sij*_*der 6 ruby activerecord ruby-on-rails
假设我有Book模型和Author模型.我想列出按书籍数量排序的所有作者.最好的方法是什么?
我知道如何在SQL中执行此操作,方法是使用嵌套选择或使用某些连接执行.但我想知道的是如何使用ActiveRecord很好地完成这项工作.
取自http://www.ruby-forum.com/topic/164155
Book.find(:all, :select => "author_id, count(id) as book_count", :group => "author_id", :order => "book_count")
Run Code Online (Sandbox Code Playgroud)
正如Kevin建议的那样,counter_cache是最简单的选择,绝对是我会用的.
class Author < ActiveRecord::Base
has_many :books, :counter_cache => true
end
class Book < ActiveRecord::Base
belongs_to :author
end
Run Code Online (Sandbox Code Playgroud)
如果您使用的是Rails 2.3,并且您希望这是默认排序,则可以使用新的default_scope方法:
class Author < ActiveRecord::Base
has_many :books, :counter_cache => true
default_scope :order => "books_count DESC"
end
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
现在您没有安装counter_cache,但是如果您根据counter_cache约定命名数据库books_count中的字段,那么当您查找时:
@Author = Author.find(1)
puts @author.books.size
Run Code Online (Sandbox Code Playgroud)
它仍将使用计数器缓存的数字,而不是执行数据库查找.当然这仅在rails应用程序更新表时才有效,因此如果另一个应用程序执行了某些操作,那么在rails应用程序返回之前,您的数字可能会不同步,必须保存.解决这个问题的唯一方法是,如果你的rails应用程序不经常查找事情以使其无关紧要,则可以同步数字.
小智 7
我建议将计数缓存书计数作为Author的另一个属性(Rails通过关联选项支持此项).这是迄今为止最快的方法,Rails非常适合确保它保持计数同步.
| 归档时间: |
|
| 查看次数: |
5729 次 |
| 最近记录: |