如何排序的作者通过他们的书算用ActiveRecord?的书、作者、ActiveRecord

2023-09-08 15:46:45 作者:心碎了還剩下什么

让我们说我有书模型和作者的模型。我想列出所有作者的排序条件为他们的书计数。什么是做到这一点的最好方法是什么?

Let's say I have Book model and an Author model. I want to list all authors sorted by their book count. What's the best way to do that?

我知道如何做到这一点的SQL,无论是与嵌套查询或与一些加盟做在那里..研究。但我想知道的是如何做到这一点很好地与ActiveRecord的。

I know how to do this in SQL, either by doing where .. in with a nested select or with some join. But what I'd like to know is how to do this nicely with ActiveRecord.

推荐答案

随着凯文曾建议,counter_cache是​​最简单的选择,我会用肯定的东西。

As Kevin has suggested, counter_cache is the easiest option, definitely what I would use.

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

class Book < ActiveRecord::Base
  belongs_to :author
end

如果你正在使用Rails 2.3,你想这是默认的排序,你可以使用新的default_scope方式:

And if you are using Rails 2.3 and you would like this to be the default ordering you could use the new default_scope method:

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

  default_scope :order => "books_count DESC"
end

books_count是执行反缓存行为领域,有可能是一个比直接在默认范围内使用它更好的办法,但它给你的想法,并把工作做好。

books_count is the field that performs the counter caching behaviour, and there is probably a better way than using it directly in the default scope, but it gives you the idea and will get the job done.

编辑:

在回应意见,询问是否counter_cache将工作,如果非Rails应用程序改变了数据,那么它可以,但不是在默认方式为Rails的递增和递减计数器,在节省时间。你可以做的是写你自己的实现在after_save的回调。

In response to the comment asking if counter_cache will work if a non rails app alters the data, well it can, but not in the default way as Rails increments and decrements the counter at save time. What you could do is write your own implementation in an after_save callback.

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公约那么当你看到了:

Now you don't have a counter_cache installed, but if you name the field in the database books_count as per the counter_cache convention then when you look up:

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

将仍然使用进行数据库查询柜台缓存数代替。当然,当Rails应用程序更新表,这只会工作,如果另一个应用程序做一些事情,然后你的号码可能不同步,直到Rails应用程序回来一个有救。解决这个,我能想到的唯一的办法就是cron作业同步数字,如果你的Rails应用程序不就查找起来的东西往往足以令它并不重要。

It will still use the counter cached number instead of performing a database lookup. Of course this will only work when the rails app updates the table, so if another app does something then your numbers may be out of sync until the rails application comes back an has to save. The only way around this that I can think of is a cron job to sync numbers if your rails app doesn't do lookup up things often enough to make it not matter.