我想检查 ActiveRecord 对象上的属性是否已被修改。目前我正在这样做:
prev_attr = obj.attributes
<- this will give me back a Hash with attr name and attr value
然后,稍后,我再次获取属性并比较 2 个哈希值。还有别的办法吗?
确实还有另一种方法。你可以这样做:
it "should not change sth" do
expect {
# some action
}.to_not change{subject.attribute}
end
请参阅https://www.relishapp.com/rspec/rspec-expectations/v/2-0/docs/matchers/expect-change。
您可以使用ActiveRecord::Dirty。它为您的模型提供了
changed?
和 saved_changes?
方法,如果模型的任何属性实际发生更改,则这些方法为 true,否则为 false。每个属性还具有 _changed?
方法,例如model.subject_changed?
如果与从数据库读取对象时相比该属性发生了更改,则该属性为真。
要比较属性值,您可以使用
model.subject_was
,这将是实例化对象时属性的原始值。或者您可以使用 model.changes
,它将返回一个以属性名称为键的哈希值以及一个包含每个更改属性的原始值和更改值的 2 元素数组。
示例:
it {
subject
expect(user).not_to be_changed
expect(user).not_to be_saved_changes
}
您应该能够使用等式匹配器 - 这对您不起作用吗?
a = { :test => "a" }
b = { :test => "b" }
$ a == b
=> false
b = { :test => "a" }
$ a == b
=> true
或者使用你的例子:
original_attributes = obj.attributes
# do something that should *not* manipulate obj
new_attributes = obj.attributes
new_attributes.should eql original_attributes
不是一个完美的解决方案,但正如这里提到的,由于可维护性,我更喜欢它。
属性会被缓存,并且由于它们不会直接更改,因此如果您想一次检查所有属性,则必须重新加载它们:
it 'does not change the subject attributes' do
expect {
# Action
}.to_not change { subject.reload.attributes }
end
如果可以的话,请避免重新加载,因为您正在强制向数据库发出另一个请求。