我写嗨,但是我不会放过它,所以我会写更长的句子:)顺便说一下。
看起来我的示波器无效。
我写了那个范围:
scope :ordered, ->(field, order) { except(:order).order("#{field} #{order}") }
但在检查SQL时返回以下内容:
irb >p.levels.ordered("name", "ASC").to_sql
=> "SELECT \"levels\".* FROM \"levels\" WHERE (\"levels\".pie_id = 6 AND (\"levels\".\"parent_id\" = 0)) ORDER BY position ASC, name ASC"
注意:position ASC
不应该在那里
但是在我的范围之前添加除外...
irb > p.levels.except(:order).ordered("name", "ASC").to_sql
=> "SELECT \"levels\".* FROM \"levels\" WHERE (\"levels\".pie_id = 6 AND (\"levels\".\"parent_id\" = 0)) ORDER BY name ASC" `
是否在范围内可用?或者你看到任何可以帮助我的东西吗?
Ruby 1.9.2p290
Rails 3.0.14
THX
答案 0 :(得分:3)
您可能已经认为可以使用reorder
来实现目标。所以这是我的理论,为什么reorder
有效,except
没有。
重要的是,order
,where
,except
等方法由ActiveRecord::Relation
的实例处理,而范围则为ordered
。您的示例中的ActiveRecord::Relation
由some_relation.order(:x)
的实例委托给您的模型类。
some_relation
方法只会返回:x
的新副本,其中order_values
已添加到some_relation.except(:order)
列表中。同样,some_relation
会返回空order_values
的{{1}}副本。只要调用链包含这种关系方法,except
就像我们期望的那样工作。
当scope作为lambda返回关系实现时,对scope方法的调用最终会导致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
的效果。如果我们合并b
和b
,并且a
没有订单设置,但reorder
没有,那么结果仍然会有订单。现在reorder_flag
通过一个技巧解决它:它在关系上设置特殊标记merge
,控制order_values
携带default_scope
的方式。
这是我的测试样本。我正在使用Product#scoped
将订单注入Level#scoped
。在您的示例中,订单可能会通过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
具有reorder_flag
次序,因此它会显示在结果中,尽管它已从范围返回的关系中清除。
以下是相关来源的链接列表:
答案 1 :(得分:1)
添加了您在模型中定义的范围
scope :ordered, ->(field, order) { except(:order).order("#{field} #{order}") }
尝试了不同的组合和所有工作
a.inspection_serial_numbers.ordered('part_serial_number', 'DESC').except(:order).ordered('id', 'DESC').to_sql
=> "SELECT `inspection_serial_numbers`.* FROM `inspection_serial_numbers` WHERE `inspection_serial_numbers`.`inspection_master_id` = 1 ORDER BY id DESC"
a.inspection_serial_numbers.ordered('part_serial_number', 'DESC').except(:order).ordered('id', 'DESC').except(:order).ordered('is_active', 'ASC').to_sql
=> "SELECT `inspection_serial_numbers`.* FROM `inspection_serial_numbers` WHERE `inspection_serial_numbers`.`inspection_master_id` = 1 ORDER BY is_active ASC"
即使您在任何组合中多次将“有序”范围与“除外”组合在一起,最后“有序”范围也会用于排序
a.inspection_serial_numbers.ordered('part_serial_number', 'DESC').ordered('id', 'ASC').except(:order).ordered('id', 'DESC').to_sql
=> "SELECT `inspection_serial_numbers`.* FROM `inspection_serial_numbers` WHERE `inspection_serial_numbers`.`inspection_master_id` = 1 ORDER BY id DESC"
如果你想删除所有范围,请使用'unscoped'
a.inspection_serial_numbers.ordered('id', 'ASC').unscoped.ordered('part_serial_number', 'DESC').to_sql
=> "SELECT \"inspection_serial_numbers\".* FROM \"inspection_serial_numbers\" ORDER BY part_serial_number DESC"
请参阅http://apidock.com/rails/ActiveRecord/SpawnMethods/except和http://apidock.com/rails/ActiveRecord/Base/unscoped/class
答案 2 :(得分:0)