我在运行规范时遇到了一个奇怪的行为。
此代码不起作用(baz.viewed
未更新),除非我取消注释第baz.reload
行。
describe "#..." do
it "..." do
baz = user.notifications.create!(title: "baz")
baz.update_attribute(:created_at, Time.now + 3.day)
# it sets `viewed` to `true` in the model to which `baz` is referred.
user.dismiss_latest_notification!
# baz.reload
baz.viewed.should == true
end
end
我没有使用Spork
或Guard
运行规范,但无论如何都不会重新加载此模型。
为什么会发生这种情况?或者,通常的做法是在规范中调用.reload
方法?
答案 0 :(得分:4)
让我让这个案例更加清晰:
当行baz = user.notifications.create!(title: "baz")
被执行时,会发生两件事:
1-新的通知行将添加到数据库中。
2-在内存中创建一个对象,表示该行,并且可以使用变量baz
引用。
请注意,baz
的查看值为false(同时行也是如此)。
现在我没有看到方法的实际实现
user.dismiss_latest_notification!
但是既然你没有传递任何变量,我肯定知道你有一个本着精神的代码:
def dismiss_latest_notification!
latest_notification = self.notifications.last
latest_notification.viewed = true
latest_notification.save!
end
这里重要的一行是
latest_notification = self.notifications.last
在内存中创建一个对象,表示同一行baz
,但存储在另一个变量中 - latest_notification。
现在,您有两个表示DB中同一行的变量。当您在latest_notification上执行保存时,将使用正确的查看值更新数据库,但不会以任何方式更新变量baz
以反映此更改。您别无选择,只能通过对其执行reload
来强制使用最新值从数据库进行更新。
我认为摆脱重装的正确方法是稍微改变测试:
而不是
baz.viewed.should == true
使用:
user.notifications.last.viewed.should be_true
在我看来,它更适合这个特定测试的目的。