Rails中的范围与类方法3

时间:2012-01-25 19:02:29

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

基于Rails 3 API,范围和类方法之间的差异几乎不存在。

class Shipment < ActiveRecord::Base
  def self.unshipped
    where(:shipped => false)
  end
end

相同
scope :unshipped, where(:shipped => false)

然而,我发现我有时会使用它们得到不同的结果。

虽然它们都生成相同的,正确的SQL查询,但在调用时,范围似乎并不总是返回正确的值。看起来这个问题只发生在它在方法中两次调用相同的方式时,尽管是在不同的货件上。第二次调用时,使用范围时它会返回与第一次相同的操作。然而,如果我使用类方法,它可以正常工作。

使用范围时是否会出现某种查询缓存?

编辑:

order.line_items.unshipped

上面的行是调用范围的方式。订单有很多line_items。

generate_multiple_shipments方法被调用两次,因为测试会创建一个订单并生成货件以查看其数量。然后它会对订单进行更改并重新生成货件。但是,group_by_ship_date返回与订单的第一次迭代相同的结果。

def generate_multiple_shipments(order)
  line_items_by_date = group_by_ship_date(order.line_items.unshipped)

  line_items_by_date.keys.sort.map do |date|
    shipment = clone_from_order(order)
    shipment.ship_date = date
    line_items_by_date[date].each { |line_item| shipment.line_items << line_item }
    shipment
  end
end

def group_by_ship_date(line_items)    
  hash = {}
  line_items.each do |line_item|
    hash[line_item.ship_date] ||= []
    hash[line_item.ship_date] << line_item
  end
  hash
end

2 个答案:

答案 0 :(得分:1)

假设您正在引用Rails 3.1,范围可能会受到模型上可能定义的默认范围的影响,而类方法则不会。

答案 1 :(得分:1)

我认为您的调用不正确。您应该添加所谓的查询方法来执行范围,例如allfirstlast,即:

order.line_items.unshipped.all

我观察到一些不一致的情况,特别是在rspec中,通过添加查询方法可以避免这种不一致。

你没有发布你的测试代码,所以很难准确地说,但是我的优势在于你修改了相关记录后,你必须强制重新加载,因为查询缓存并不总是足够智能来检测变化。通过将true传递给关联,您可以强制重新加载关联并重新运行查询:

order.line_items(true).unshipped.all