Open
Description
I ran into this today while trying to use the new have_attributes
matcher:
widget = create(Widget, name: 'widget', package: 'single')
form_attributes = {
id: widget.to_param,
widget: {
name: 'A new name',
package: 'bulk',
}
}
expect {
put :update, form_attributes, valid_session
}.to change{ Widget.find(widget.id) }.to have_attributes(
name: 'A new name',
package: 'bulk',
)
Running this fails with:
expected result to have changed to have attributes { ... }, but did not change
Root Cause
The root of this issue is this line from the RSpec::Matchers::BuiltIn::ChangeDetails
internal implementation used by the change
matcher:
@actual_before != @actual_after
It's attempting to check that the objects aren't equal, thus not changing. However, ActiveRecord
overrides ==
to mean do these objects have the same id
value. If so, then they are the same object. This causes change
to fail.
Workarounds
- Call
dup
onActiveRecord
objects in thechange
block. This will remove theid
resulting inActiveRecord
to fall back on a more intensive attribute match. - Call
ActiveRecord#attributes
to get the attribute list and use RSpec's standard hash matchers such asinclude
.