我不确定这是否是范围或其他问题,但我在更新测试中的对象时遇到问题:单位。
有趣的是,所有功能在开发模式下都能完美运行,但只要切换到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
新数量(根据上一个日志而变化)。 有趣的是,在函数本身中,数量字段更新为两个。它甚至可以保存到SQL数据库中。但是当我调用cart.line_items时,它甚至有更新的字段,但它没有保存新的数量(根据上一个日志已经改变)。
答案 0 :(得分:3)
默认情况下,Rails没有身份映射。这意味着无论何时执行LineItem.find(1)
和另一个LineItem.find(1)
,您将获得两个单独的对象,这些对象是从数据库中的同一行数据创建的,但它们之间没有任何连接。如果其中一个被更改并保存到数据库中,则另一个对象将不知道它并且仍然具有旧数据。
在您的示例中,您正在执行line_items.find_by_product_id(product.id)
,它将执行查找并每次返回一个新对象。与先前加载到LineItem
的任何cart.line_items
对象无关。
有两种方法可以更新陈旧对象的数据。其中之一是.reload
方法,它将从数据库重新加载一个对象的所有数据。另一种选择是将true
传递给cart.line_items
关联。像cart.line_items(true)这样的调用将强制对数据库进行新查询以获取所有订单项。
此错误仅在测试期间遇到您的原因很简单:在开发模式下,插入和读取通常在两个单独的请求中完成,因此每次都从数据库中新加载所有对象。