0

我不确定这是否是范围问题或其他问题,但我在更新 test:unit 中的对象时遇到问题。

有趣的是,所有功能在开发模式下都能完美运行,但是一旦我切换到 rake test:unit,它就全部中断了。

以下是相关代码:

  class Cart < ActiveRecord::Base

  def add_product(product)
    current_item = line_items.find_by_product_id(product.id)
    if current_item
      Rails::logger.debug "Incrementing quantity"
      Rails::logger.debug current_item.quantity
      current_item.quantity += 1
      Rails::logger.debug current_item.quantity
    else
      current_item = line_items.build(product_id: product.id,
                                     price: product.price)
    end
    Rails::logger.debug "Added Product"
    Rails::logger.debug current_item.quantity
    current_item
  end

和相关的测试

  test "create new cart with one item added twice" do
    cart = Cart.new
    cart.add_product(products(:one)).save!
    assert_equal 1, cart.line_items.size
    assert_equal 36.00, cart.total_price
    Rails::logger.debug cart.line_items.to_a
    cart.add_product(products(:one)).save!
    Rails::logger.debug "Added second item"
    Rails::logger.debug cart.line_items.to_a
    Rails::logger.debug cart.total_price
    assert_equal 1, cart.line_items.size
    assert_equal 72.00, cart.total_price
  end

这是日志输出:

Incrementing quantity
1
2
Added Product
2
   (0.1ms)  SAVEPOINT active_record_1
   (0.3ms)  UPDATE "line_items" SET "quantity" = 2, "updated_at" = '2013-01-18 15:27:06.958210' WHERE "line_items"."id" = 980190963
   (0.1ms)  RELEASE SAVEPOINT active_record_1
Added second item
[#<LineItem id: 980190963, product_id: 1, cart_id: nil, created_at: "2013-01-18 15:27:06", updated_at: "2013-01-18 15:27:06", quantity: 1, price: 36>]
36

ew 数量(根据上次日志已更改)。有趣的是,在函数本身中,数量字段正在更新为两个。它甚至可以保存到 SQL 数据库中。但是当我调用cart.line_items时,它甚至有更新的字段,但它没有保存新的数量(根据最后的日志已经改变)。

4

1 回答 1

3

默认情况下,Rails 没有身份映射。这意味着,无论何时执行一个LineItem.find(1)和另一个LineItem.find(1),您都会得到两个单独的对象,它们是从数据库中的同一行数据创建的,但它们之间没有任何连接。如果其中一个被更改并保存到数据库中,另一个对象将不知道它并且仍然拥有旧数据。

在您的示例中,您正在执行line_items.find_by_product_id(product.id)的操作每次都会进行查找并返回一个新对象。与LineItem之前加载到cart.line_items.

有两个选项可以更新陈旧对象的数据。其中之一是.reload将重新加载数据库中一个对象的所有数据的方法。另一种选择是将 a 传递truecart.line_items关联。像 cart.line_items(true) 这样的调用将强制对数据库进行新查询以获取所有订单项。

这个 bug 只在测试时出现的原因很简单:在开发模式下,插入和读取通常是在两个单独的请求中完成的,因此每次都是从数据库中新加载的所有对象。

于 2013-01-18T15:48:57.420 回答