Reputation: 13842
I have a User
model.
A user
has many integrations
.
An integration
is join to a profile
via integration_profiles
which contains a column data
.
I want to eager load all of a user's profiles.
class Integration < ActiveRecord::Base
has_many :integration_profiles
has_many :profiles, through: :integration_profiles
end
class IntegrationProfile < ActiveRecord::Base
belongs_to :integration
belongs_to :profile
end
class Profile < ActiveRecord::Base
has_many :integration_profiles
has_many :integrations, through: :integration_profiles
end
I tried this:
all = User.first.integrations.includes(:profiles)
But I when I did all.count
=> 2
But when I do
all = User.first.integrations.joins(:profiles)
all.count
=> the correct total
Should I be using includes or joins? I have always used includes so not sure why this isn't working here
Upvotes: 6
Views: 6759
Reputation: 53018
When you do
all = User.first.integrations.joins(:profiles)
all.count
the integrations records would be counted for the first User
and with an inner join query on profiles
.
And when you do
all = User.first.integrations.includes(:profiles)
all.count
again you get integrations count BUT without join query with profiles as profiles are eager loaded with separate queries because of includes
It seems that you simply want the profiles
count associated to a given user
. The best way to achieve this would be, to create an association between User
and Profile
model
User ==> has_many :profiles, through: :integration
Once you do that, you can directly access User.first.profiles.count
to get the count of all associated profiles of a particular user.
The other option would be (if you don't want to go with above option) to loop through all integrations
and sum up all profiles.count
for every integration.
Choose the option that best suits your needs.
Upvotes: 3
Reputation: 749
Query 1
all = User.first.integrations.includes(:profiles)
all.count
is returning count of integrations and not of profile. Profile is loaded eagerly.
If you want to know the count of profile then it needs to be done in this way.
ar = [ ]
all.each do |a|
ar << a.profiles.count
end
ar.reduce(:+)
will give you the same count when you run Query 2.
Query 2
all = User.first.integrations.joins(:profiles)
all.count
In case of Query 2, its returning you integrations from integrartion_profiles table.
Select users from users limit 1;
Select integrations from integrations INNER JOIN integration_profiles on integration_profiles.integration_id = integrations.id where integrations.user_id = 'id of user'
To know more about it call .to_sql on Query 1 and Query 2.
If you want to do eager loading then use of includes is the preferred option.
Upvotes: 0