4

我写了嗨,但SO不会让它,所以我写更长的句子:)顺便说一句嗨。

看起来我的范围不起作用。

我写了那个范围:

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" `

除了在范围内可用吗?或者你有什么可以帮助我的吗?

红宝石 1.9.2p290

导轨 3.0.14

谢谢

4

3 回答 3

3

您可能已经想到可以通过使用reorder. 所以这是我关于为什么reorder有效和except无效的理论。

重要的是,像order, where,之类的方法except由 , 的实例处理ActiveRecord::Relation,而范围(例如ordered来自您的示例)则由 的实例委托ActiveRecord::Relation给您的模型类。

some_relation.order(:x)方法只是返回添加到其列表中的some_relation新副本。同样,将返回with empty的副本。只要调用链包含这样的关系方法,就可以按我们的预期工作。:xorder_valuessome_relation.except(:order)some_relationorder_valuesexcept

对作用域方法的调用,当作用域实现为 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如果我们合并aand 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顺序,尽管它已从范围返回的关系中清除,但它仍出现在结果中。

以下是相关来源的链接列表:

于 2012-09-04T21:10:57.057 回答
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/excepthttp://apidock.com/rails/ActiveRecord/Base/unscoped/class

于 2012-08-30T07:48:11.103 回答
0

方法的顺序可能是错误的。

应该写order("#{field} #{order}").except(:order)

导轨指南

于 2012-08-19T13:51:59.977 回答