5

我想检查是否没有修改 ActiveRecord 对象的属性。目前我正在这样做:

prev_attr = obj.attributes<- 这将给我一个带有 attr 名称和 attr 值的哈希

然后,稍后,我再次获取属性并比较 2 个哈希值。还有其他方法吗?

4

4 回答 4

11

确实还有另一种方式。你可以这样做:

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

于 2012-05-07T10:33:24.983 回答
3

您可以使用ActiveRecord::Dirty。它为您的changed?模型提供了一种方法,如果模型的任何属性实际更改,则该方法为真,否则为假。您还拥有_changed?每个属性的方法,例如model.subject_changed?,如果与从数据库中读取对象时相比,该属性发生了更改,则该方法是真实的。

要比较属性值,您可以使用model.subject_was在实例化对象时属性具有的原始值。或者您可以使用model.changeswhich 将返回一个以属性名称作为键的散列和一个包含每个更改属性的原始值和更改值的 2 元素数组。

于 2012-05-07T11:29:52.033 回答
2

您应该能够使用平等匹配器- 这对您不起作用吗?

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
于 2012-05-07T08:28:17.337 回答
1

不是一个完美的解决方案,但正如这里提到的,由于可维护性,我更喜欢它。

属性被缓存,并且由于它们没有直接更改,如果您想一次检查它们,则必须重新加载它们:

it 'does not change the subject attributes' do
  expect {
    # Action
  }.to_not change { subject.reload.attributes }
end

如果可以,请避免重新加载,因为您正在强制向数据库发出另一个请求。

于 2018-07-21T00:19:48.730 回答