Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the results of other tables using includes or joins in Ruby on Rails

I want to query the results of private_classes. The scenario is:

class PrivateClass < ActiveRecord::Base
  belongs_to :private_school
  has_many :lesson_plans
end

class JoinedPrivateSchool < ActiveRecord::Base
  belongs_to :student
  belongs_to :private_school
end

class PrivateSchool < ActiveRecord::Base
  belongs_to :teacher
  has_many :private_classes
  has_many :joined_private_schools
end

class Student < ActiveRecord::Base
  has_many :joined_private_schools
end

JoinPrivateSchool has the attribute private_school_id.

I am doing:

s = Student.find(9)

s.joined_private_schools

which results in:

=> #<ActiveRecord::Associations::CollectionProxy [#<JoinedPrivateSchool id: 8,
 user_id: 73, student_id: 9, private_school_id: 28, created_at: "2017-02-16 
12:38:37", updated_at: "2017-02-16 12:38:37">, #<JoinedPrivateSchool id: 9,
 user_id: 73, student_id: 9, private_school_id: 33, created_at: "2017-02-16 
12:42:01", updated_at: "2017-02-16 12:42:01">, #<JoinedPrivateSchool id: 12, 
user_id: 73, student_id: 9, private_school_id: 32, created_at: "2017-02-16 
13:19:02", updated_at: "2017-02-16 13:19:02">]>

If I do:

c = s.joined_private_schools.includes(private_school: :private_classes)

it results in:

JoinedPrivateSchool Load (0.6ms)  SELECT "joined_private_schools".* FROM 
"joined_private_schools" WHERE "joined_private_schools"."student_id" = $1 
 [["student_id", 9]]


PrivateSchool Load (0.9ms)  SELECT "private_schools".* FROM "private_schools" 
WHERE "private_schools"."id" IN (28, 33, 32)  ORDER BY 
"private_schools"."created_at" DESC


PrivateClass Load (0.7ms)  SELECT "private_classes".* FROM "private_classes" 
WHERE "private_classes"."private_school_id" IN (33, 32, 28)  ORDER BY 
"private_classes"."created_at" DESC


=> #<ActiveRecord::AssociationRelation [#<JoinedPrivateSchool id: 8, user_id: 
73, student_id: 9, private_school_id: 28, created_at: "2017-02-16 12:38:37",
 updated_at: "2017-02-16 12:38:37">, #<JoinedPrivateSchool id: 9, user_id: 73,
 student_id: 9, private_school_id: 33, created_at: "2017-02-16 12:42:01", 
updated_at: "2017-02-16 12:42:01">, #<JoinedPrivateSchool id: 12, user_id: 73,
 student_id: 9, private_school_id: 32, created_at: "2017-02-16 13:19:02", 
updated_at: "2017-02-16 13:19:02">]> 

But that is still the wrong results.

I need to get the results of private_classes using one query so I can avoid multiple each loops.


2 Answers

If you want to have PrivateClass, you're starting from the wrong point (User). You need to start from PrivateClass joining all the intermediary tables and using the user id as condition:

PrivateClass.joins(private_school: :user).where(user: {id: 9})

# or a little more performant (avoids one join)

PrivateClass.joins(:private_school).where(private_school: {user_id: 9})
like image 144
lcguida Avatar answered Dec 13 '25 16:12

lcguida


You can use :through on associations (at least in Rails 4.2)
I updated this, I first missed that you wanted private_classes

class JoinedPrivateSchool < ActiveRecord::Base
  belongs_to :student
  belongs_to :private_school
  has_many :private_classes, through: :private_schools
end

class Student < ActiveRecord::Base
  has_many :joined_private_schools
  has_many :private_classes, through: :joined_private_schools
end

s = Student.find(9)
s.private_classes
like image 40
244an Avatar answered Dec 13 '25 14:12

244an



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!