范围使用除了不工作Rails

时间:2012-08-17 16:37:53

标签: ruby-on-rails-3 scope except

我写嗨,但是我不会放过它,所以我会写更长的句子:)顺便说一下。

看起来我的示波器无效。

我写了那个范围:

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

3 个答案:

答案 0 :(得分:3)

您可能已经认为可以使用reorder来实现目标。所以这是我的理论,为什么reorder有效,except没有。

重要的是,orderwhereexcept等方法由ActiveRecord::Relation的实例处理,而范围则为ordered。您的示例中的ActiveRecord::Relationsome_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的效果。如果我们合并bb,并且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/excepthttp://apidock.com/rails/ActiveRecord/Base/unscoped/class

答案 2 :(得分:0)

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

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

请参阅rails guide