I have the following model
class Event < ActiveRecord::Base
has_many :attendances
class Attendance < ActiveRecord::Base
belongs_to :user
class Student < User
has_one :student_detail
class StudentDetail < ActiveRecord::Base
belongs_to :school
class Staff < User
has_one :staff_detail
class StaffDetail < ActiveRecord::Base
The StudentDetail and StaffDetails have additional information, I am trying to avoid having it all in one STI user table due to having to work with something similar to concrete class per table pattern
I can do this easily enough
Event.includes(:attendances => :user).where(...)
but I want to be able to includes depending on user type e.g.
Event.includes(attendances: {:user => :student_details })
This will fail as some of the users are Staff objects.
I realise rails won't support this out of the box, but anyone have any tricks to get this to work
best solution right now would be split user on attendance to student and staff i.e.
class Attendance < ActiveRecord::Base
belongs_to :student, -> {includes(:staff_detail) }
belongs_to :staff, -> {includes(:student_detail) }
#belong_to :user
which isn't ideal. Anyone have any tips? way to solve this.
The easiest way is to just move the has_one
associations down on to user. Since only Staff
records will have staff_details
, the preloading will just work.
class User < ActiveRecord::Base
has_one :staff_detail
has_one :student_detail
end
class Staff < User; end
class Student < User; end
That's not ideal though. To customise preloading further, you can use the Preloader
class in Rails. First, load all the records without any includes, then iterate over them and preload the associations you need:
events = Event.includes(:attendances => :user)
users = events.users.flatten
users.group_by(&:class).each do |klass, records|
associations = {
Staff: [:staff_detail],
Student: [:student_detail]
}.fetch(klass, [])
ActiveRecord::Associations::Preloader.new(records, associations).run
end
Note that this API changed in Rails 4. In versions 3 and earlier, you just used the preload_associations
method.
A while back I wrote a blog post about this same problem which includes a couple of other neat tricks (such as spec'ing that you get correct behaviour).
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