kindofgreat
kindofgreat

Reputation: 900

Confusion about ActiveRecord relation exists? method, especially with limit and offset

I am running Rails 3.2.8 and ruby 1.9.3p194.

I'm trying to better understand exactly how the exists? method works in activerecord. I am getting some weird results that I don't understand... I am going to simplify my code here for the sake of clarity.

Imagine I have a User model with a list of users.

1 Andy, m
2 Jake, m
3 Cathy, f
4 Mike, m

I have a scope for male, so:

User.male => [#< User id: 1, name: Andy, gender: male>, #< User id: 2, name: Jake, gender: male>, #< User id: 4, name: Mike, gender: male>]

OK. now:

a = User.find 1 => #<User id: 1, name: Andy, gender: male>  
b = User.find 2 => #<User id: 2, name: Jake, gender: male> 
c = User.find 3 => #<User id: 3, name: Cathy, gender: female> 
d = User.find 4 => #<User id: 4, name: Mike, gender: male> 

User.male.exists?(a) => true  
User.male.exists?(b) => true  
User.male.exists?(c) => false  
User.male.exists?(d) => true  

Ok that makes sense. However:

User.male.limit(1) => [#<User id: 1, name: Andy, gender: male>]

User.male.limit(1).exists?(a) => true  
User.male.limit(1).exists?(b) => true  
User.male.limit(1).exists?(c) => false  
User.male.limit(1).exists?(d) => true  

Why does exists?(b) and exists?(d) return true? Is it because the limit doesn't actually change the query which is still all male users, and limit(1) is simply a display thing? I can buy this, but then what would the correct query be if I only wanted exists?(a) to return true, and everything else to return false?

Okay, now this really confuses me completely:

User.male.limit(1).offset(1) => [#<User id: 2, name: Jake, gender: male>]  

User.male.limit(1).offset(1).exists?(a) => false
User.male.limit(1).offset(1).exists?(b) => false
User.male.limit(1).offset(1).exists?(c) => false
User.male.limit(1).offset(1).exists?(d) => false

Why does everything here return false? I want exists?(b) to return true, and I can't figure out at all why it doesn't. If anyone can enlighten me, I would be very grateful. I looked through the docs to no avail.

Upvotes: 4

Views: 1081

Answers (1)

Sebi
Sebi

Reputation: 669

User.male adds a where clause "gender = male"

.exists?(a) adds an extra clause "id = 1"

limit 1 just adds a limit 1 after the where clause.

So User.male.limit(1).exists?(a) will generate SELECT 1 FROMusersWHEREusers.id= 1 AND (gender =male) LIMIT 1

So the reason why .exists?(x) works is because it adds the id to the where clause and thus selects the relevant record.

Also the offset(1) wouldn't work because you only get 1 matching record when you put the exists?(x) and adding an offset(1) to that would mean that it should look for records after that one.

Upvotes: 1

Related Questions