How to test for (ActiveRecord) object equality
Rails deliberately delegates equality checks to the identity column. If you want to know if two AR objects contain the same stuff, compare the result of calling #attributes on both.
Testing equality for ActiveRecord::Relation
It is worth noting that an ActiveRecord::Relation
just defines a database query. It only holds information about where
conditions, limit
, joins
etc. clauses. But that query is not performed until a result is actually requested.
Therefore it makes sense that two relations that would end up returning the same result under a certain condition are not treated as equal. Because running both queries under another condition might return different results: Maybe because they return timestamps or the return is randomly ordered.
The query is performed once a result is needed: When you call each
or all
for example. Or in your example: size
or first
. Once the query ran the actual result is returned (and not a Relation
object anymore). Therefore all later comparisons return true
.
ActiveRecord object equality
Answering my own question (which is irrelevant).
All the equality checks DO work as expected (and described in the docs).
I assume the reason it did not work for me is that I run autotest
and something could be cached or some other mythical reason that I can't explain right now.
To summarise, all the following assertions are indeed passing:
a = Factory.create(:user)
b = User.find_by_email(a.email) # b is logically same as a
a.id.should == b.id
a.should == b
a.should eql b
User.find_by_email(a.email).should == User.find_by_email(a.email)
a.should == User.find_by_email(a.email)
b.should == User.find_by_email(a.email)
Equality test on three or more objects
[a,b,c,d].any?{|x| x != a}
or
array.any?{|x| x != array.first}
Alternatively, the #all? method may read more intuitively for some:
array.all? {|x| x == array.first }
Comparing ActiveRecord objects with Rspec
A shorter way to write the above would be actual.attributes.except(:id, :updated_at, :created_at)
.
If you are using this a lot, you can always define your own matcher like this:
RSpec::Matchers.define :have_same_attributes_as do |expected|
match do |actual|
ignored = [:id, :updated_at, :created_at]
actual.attributes.except(*ignored) == expected.attributes.except(*ignored)
end
end
Put this into your spec_helper.rb
you can now say in any example:
User.first.should have_same_attributes_as(User.last)
Good luck.
Related Topics
How to Avoid Running Activerecord Callbacks
How to Find and Return a Duplicate Value in Array
Redirect_To Using Post in Rails
Best Practices With Stdin in Ruby
Using Rails Serialize to Save Hash to Database
How to Determine If One Array Contains All Elements of Another Array
Test If String Is a Number in Ruby on Rails
Confusion With the Assignment Operation Inside a Falsy 'If' Block
Rails :Dependent =≫ :Destroy VS :Dependent =≫ :Delete_All
Ruby Function to Remove All White Spaces
Save Image from Url by Paperclip
How to Split (Chunk) a Ruby Array into Parts of X Elements
Best Way to Create Custom Config Options For My Rails App
Find_Spec_For_Exe': Can't Find Gem Bundler (≫= 0.A) (Gem::Gemnotfoundexception)
Valid Email Address Regular Expression