Reputation: 900
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
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 FROM
usersWHERE
users.
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