15

所以基本上我有两个课程,BookAuthor。书籍可以有多个作者,作者可以有多个书籍。书籍具有以下默认范围。

default_scope :order => "publish_at DESC"

在作者显示页面上,我想列出与该作者相关的所有书籍,所以我说以下...

@author = Author.find(params[:id])
@books = @author.books

到目前为止一切都很好。author#show 页面列出了属于该作者的所有书籍,按出版日期排序。

我还在研究一种能够按一本书的受欢迎程度排序的宝石。

@books = @author.books.sort_by_popularity

问题是每当它尝试排序时,default_scope 总是会妨碍它。如果我在它摆脱作者关系并返回数据库中的每一本书之前尝试取消它的范围。例如

@books = @author.books.unscoped.sort_by_popularity # returns all books in database

我想知道我是否可以使用ActiveRelation except() 方法 来做这样的事情(看起来它应该可以工作但它没有。它忽略了顺序,而不是当它是 default_scope 顺序时)

def sort_by_popularity
  self.except(:order).do_some_joining_magic.order('popularity ASC')
  #    |------------|                       |---------------------|
end

关于为什么这不起作用的任何想法?关于如何让它以不同的方式工作的任何想法?我知道我可以摆脱 default_scope 但我想知道是否还有其他方法可以做到这一点。

4

2 回答 2

31

您应该可以使用reorder来完全替换现有的 ORDER BY:

reorder(*args)
将关系上定义的任何现有订单替换为指定订单。

所以是这样的:

def self.sort_by_popularity
  scoped.do_some_joining_magic.reorder('popularity ASC')
end

而且我认为您想为此使用类方法,而scoped不是self但我不知道整个上下文,所以也许我错了。

我不知道为什么except不起作用。似乎在default_scope最后(有点)而不是在开始时应用,但我没有过多地研究它。

于 2012-03-16T23:58:52.727 回答
1

您可以在不丢失default_scope或其他订购的情况下做到这一点

@books.order_values.prepend 'popularity ASC'
于 2018-07-22T08:34:47.390 回答