您可能已经想到可以通过使用reorder
. 所以这是我关于为什么reorder
有效和except
无效的理论。
重要的是,像order
, where
,之类的方法except
由 , 的实例处理ActiveRecord::Relation
,而范围(例如ordered
来自您的示例)则由 的实例委托ActiveRecord::Relation
给您的模型类。
some_relation.order(:x)
方法只是返回添加到其列表中的some_relation
新副本。同样,将返回with empty的副本。只要调用链包含这样的关系方法,就可以按我们的预期工作。:x
order_values
some_relation.except(:order)
some_relation
order_values
except
对作用域方法的调用,当作用域实现为 lambda 返回关系时,最终会合scoped
并由 lambda 返回的关系返回的模型关系:
scopes[name] = lambda do |*args|
options = scope_options.is_a?(Proc) ? scope_options.call(*args) : scope_options
relation = if options.is_a?(Hash)
scoped.apply_finder_options(options)
elsif options
scoped.merge(options) # <- here options is what returned by your :ordered lambda
else
scoped
end
extension ? relation.extending(extension) : relation
end
如果仅对要合并的关系之一执行此操作,这merge
并不能保留效果。except
如果我们合并a
and b
, andb
没有设置顺序,但是a
有,结果仍然有顺序。现在reorder
用一个技巧来解决它:它reorder_flag
在关系上设置特殊标志来控制如何merge
进行order_values
。
这是我的测试样本。我default_scope
用来将订单注入Product#scoped
. Level#scoped
在您的示例中,订单可能通过关联 in注入Pie
,看起来像has_many :levels, :order => 'position'
.
class Product < ActiveRecord::Base
default_scope order('id DESC')
scope :random_order, lambda {
r = order('random()')
puts "from lambda: " + r.order_values.inspect
r
}
end
# in console:
>> Product.scoped.order_values
=> ["id DESC"]
>> Product.random_order.order_values
from lambda: ["id DESC", "random()"]
=> ["id DESC", "id DESC", "random()"]
# now if I change the first line of lambda to
# r = except(:order).order('random()')
>> Product.random_order.order_values
from lambda: ["random()"]
=> ["id DESC", "random()"]
如您所见,由于Product.scoped
具有id DESC
顺序,尽管它已从范围返回的关系中清除,但它仍出现在结果中。
以下是相关来源的链接列表: