Daniel Chang
Daniel Chang

Reputation: 61

Why is the "where" query in rails returning a different object?

I'm testing chats between users in my app. I'm using RSpec and FactoryGirl

The test that's not passing:

it "creates a chat if one does not exist" do
  bob = create(:user, username: "bob")
  dan = create(:user, username: "dan")
  new_chat = Chat.create(user_id: @dan.id, chatted_user_id: bob.id)
  expect(Chat.where("chatted_user_id = ?", bob.id).first).to equal(new_chat)
end

The failure message says:

Failure/Error: expect(Chat.where("chatted_user_id = ?", bob.id).first).to equal(new_chat)

   expected #<Chat:70120833243920> => #<Chat id: 2, user_id: 2, chatted_user_id: 3>
        got #<Chat:70120833276240> => #<Chat id: 2, user_id: 2, chatted_user_id: 3>

   Compared using equal?, which compares object identity,
   but expected and actual are not the same object. Use
   `expect(actual).to eq(expected)` if you don't care about
   object identity in this example.

Why is my query returning a different object id?

Upvotes: 0

Views: 490

Answers (1)

Simone Carletti
Simone Carletti

Reputation: 176352

equal checks object identity. The objects you are testing are two objects (instances) referencing the same record, but they are actually different objects from a Ruby virtual machine point of view.

You should use

expect(Chat.where("chatted_user_id = ?", bob.id).first).to eq(new_chat)

To better understand the problem, look at the following example

2.0.0-p353 :001 > "foo".object_id
 => 70117320944040 
2.0.0-p353 :002 > "foo".object_id
 => 70117320962820 

Here I'm creating two identical strings. They are identical, but not equal because they are actually two different objects.

2.0.0-p353 :008 > "foo" == "foo"
 => true 
2.0.0-p353 :009 > "foo".equal? "foo"
 => false 

That's the same issue affecting your test. equal checks if two objects are actually the same at the object_id level. But what you really want to know is if they are the same record.

Upvotes: 2

Related Questions