【问题标题】:Scope using except is not working Rails使用 except 的范围不起作用 Rails
【发布时间】:2012-08-17 16:37:52
【问题描述】:

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

看来我的示波器不工作了。

我写了那个范围:

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

Rails 3.0.14

谢谢

【问题讨论】:

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


    【解决方案1】:

    您可能已经想到使用reorder 可以实现您的目标。所以这是我关于为什么 reorder 有效而 except 无效的理论。

    重要的是,orderwhereexcept 等方法由 ActiveRecord::Relation 的实例处理,而范围,例如ordered 来自您的示例,由 ActiveRecord::Relation 的实例委托给您的模型类。

    some_relation.order(:x) 方法只返回some_relation 的新副本,并将: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 的效果。如果我们合并ab,并且b 没有设置顺序,但a 有,结果仍然有顺序。现在reorder 用一个技巧来解决它:它在关系上设置特殊标志reorder_flag,它控制merge 如何携带order_values

    这是我的测试样本。我正在使用default_scope 将订单注入Product#scoped。在您的示例中,订单可能通过Pie 中的关联注入到Level#scoped,它可能看起来像has_many :levels, :order =&gt; '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 顺序,尽管它已从范围返回的关系中清除,但它仍出现在结果中。

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

    【讨论】:

    • 嘿嘿,好像不错,我马上去看看。谢谢回答
    【解决方案2】:

    添加了你在模型中定义的范围

    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

    【讨论】:

    • 嘿嘿,好像也不错,我马上去看看。谢谢回答
    【解决方案3】:

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

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

    rails guide

    【讨论】:

    • 我想要实现的是重置默认订单条件以设置新订单。您显示的方式是删除您刚刚设置的顺序。然后,查询将没有任何订单条件。请参阅您提供的链接。无论如何谢谢
    猜你喜欢
    • 2015-03-10
    • 2012-02-09
    • 2020-08-24
    • 2013-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-12
    相关资源
    最近更新 更多