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.
User.maleadds a where clause “gender = male”.exists?(a)adds an extra clause “id = 1”limit 1just adds alimit 1after the where clause.So
User.male.limit(1).exists?(a)will generateSELECT 1 FROMusersWHEREusers.id= 1 AND (gender =male) LIMIT 1So 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 theexists?(x)and adding an offset(1) to that would mean that it should look for records after that one.