Rails 3 Collection`and`因TypeError而失败

时间:2012-10-12 15:57:39

标签: ruby ruby-on-rails-3.2

在Rails 3.2.8应用程序示例中(在Ruby 1.9.3上),有以下简单设置:

class Account < ActiveRecord::Base
  has_many :line_items

  def subtotal
    line_items.sum(&:price)
  end
end

class Line_Item < ActiveRecord::Base
  belongs_to :product

  def price
    product.price * time
  end
end


account = Account.new

account.line_items.build do |item|
  item.years = 4
  item.product = Product.last
end

account.subtotal
#=> TypeError: nil can't be coerced into BigDecimal

如上所述,subtotal方法因转换错误而失败。在subtotal中,我检查了line_items.class返回的类型并获得Array。如果我将subtotal的定义更新为以下任一项,则该方法有效:

line_items.to_a.sum(&:price)
#=> #<BigDecimal:7ff4d34ca7c8,'0.0',9(36)>

line_items.map(&:price).sum
#=> #<BigDecimal:7ff4d3373b40,'0.0',9(36)>

为什么line_items.sum(&:price)的初始定义失败?

1 个答案:

答案 0 :(得分:0)

这似乎是Rails中的一个错误(至少在3.2.8中)。

在Rails 3.2.8中,has_many关联动态定义collection.sum。 虽然这没有反映在A Guide to Active Record Associations中 或ActiveRecord::Associations::ClassMethods API docs;它简要列在“{em>集合关联(一对多/多对多)”下的API中 图表,但没有再次参考。

根据code,它总是会尝试使用SQL sum来命中数据库。 但是,在此特定实例中,不保存模型。所以什么都没有 在数据库中。

所以要清楚一点:

account.line_items.sum(&:price)      # Uses Collection#sum, goes to database
account.line_items.map.sum(&:price)  # Uses Enumerable#map then Enumerable#sum

这已记录在issue #7928下;这似乎与issue #5215: "finders and scopes on has_many association on new object incorrectly query db for null foreign keys"有关。