I have the following query:
User.joins(:posts).group('users.id').having('count(user_id) > 1')
The returned class is User::ActiveRecord_Relation
.
If I call .size
on it, it returns a hash. If I call .size.size
I get the correct size returned.
Is this really how I should get the size of an ActiveRecord_Relation, or how is the correct way otherwise?
It's important to understand why you get a hash when you call #size
here.
#size
will execute a SELECT COUNT(*)
query if the association is not loaded yet. This is equivalent to calling #count
. So you get a hash.
But if somehow the association has already been loaded into memory, #size
won't execute any additional query, but will get the length of the association. In this case, the length of the hash. Try the following in console:
query = User.joins(:posts).group('users.id').having('count(user_id) > 1'); #don't load the association
query.size # => hash
query.size # => length of the previous hash
So it's not a good idea to rely on chaining #size
here unless you're sure the association wouldn't have been loaded before this. Instead, use #length
for this:
User.joins(:posts).group('users.id').having('count(user_id) > 1').length # => integer
#length
doesn't execute the additional query, and will always load the whole association into memory so it's a bit slower and is hungrier. But in practice it's usually not an issue unless you're loading a huge amount of records.
By the way, if all you want is to find number of users with more than one post, there's no need for #join
:
Post.group('user_id').having('count(user_id) > 1').length
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With