Reputation: 26758
I have a record A with id 1, it has_many B records which each have many C.
A(id=1) => [b records] => [[C records for each b]]
I need to get the count of C for the given A.
I'm pretty sure there's something to to do with joins
, groups, or
order`, but I don't know exactly what. I need a way to do this in a constant time SQL operation. No iterative queries.
Upvotes: 0
Views: 802
Reputation: 21
Assuming that I had a reason not to create the has many through association for cs through bs, I would do something like:
class A < ActiveRecord::Base
has_many :bs
# has_many :cs, through: :bs - this allows a.cs.size as has been noted here
end
class B < ActiveRecord::Base
has_many :cs
belongs_to :a
end
class C < ActiveRecord::Base
belongs_to :b
end
# you can always do this if you don't want to create the above association through bs:
a.bs.flat_map(&:cs).size
Upvotes: 1
Reputation: 18070
A couple ways
C.joins(:b).where(:bs => {:a_id => a.id}).count
or
class A < ActiveRecord::Base
has_many :bs
has_many :cs, :through => :bs
end
# Then you can do this, nice and easy to read.
# Use size, not count in case they are already loaded.
a.cs.size
or even
A.where(:id => a.id).joins(:bs => :cs).count
Upvotes: 1
Reputation: 35533
Use a has_many :through
association:
class A < ActiveRecord::Base
has_many :bs
has_many :cs, through: :bs
end
class B < ActiveRecord::Base
belongs_to :a
has_many :cs
end
class C < ActiveRecord::Base
belongs_to :b
end
Now you can do:
a.cs.count
If the has-many-through a.cs
association is something you won't regularly use, and you'd rather not add it to your model, then you can use merge
instead:
C.joins(:b).merge(a.bs).count
Upvotes: 3
Reputation: 20161
Something like:
A.join(:b => :c).where(id: 1).count("c.id")
If you already have an instance of A
:
a.b.joins(:c).count("c.id")
Upvotes: 1