dbo*_*d68 5 activerecord ruby-on-rails sti
我有以下型号
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
Run Code Online (Sandbox Code Playgroud)
StudentDetail和StaffDetails有额外的信息,我试图避免在一个STI用户表中使用它,因为必须使用类似于每个表模式的具体类的东西
我可以很容易地做到这一点
Event.includes(:attendances => :user).where(...)
Run Code Online (Sandbox Code Playgroud)
但我想能够包括取决于用户类型,例如
Event.includes(attendances: {:user => :student_details })
Run Code Online (Sandbox Code Playgroud)
这将失败,因为一些用户是Staff对象.
我意识到rails不支持开箱即用,但任何人都有任何技巧可以让它工作
现在最好的解决方案是分散用户出席学生和员工即
class Attendance < ActiveRecord::Base
belongs_to :student, -> {includes(:staff_detail) }
belongs_to :staff, -> {includes(:student_detail) }
#belong_to :user
Run Code Online (Sandbox Code Playgroud)
这不是理想的.有人有任何提示吗?解决这个问题的方法.
最简单的方法是将has_one关联向下移动到用户.由于只有Staff记录staff_details,预加载才会起作用.
class User < ActiveRecord::Base
has_one :staff_detail
has_one :student_detail
end
class Staff < User; end
class Student < User; end
Run Code Online (Sandbox Code Playgroud)
但这并不理想.要进一步自定义预加载,可以Preloader在Rails中使用该类.首先,加载所有记录而不包含任何包含,然后迭代它们并预加载所需的关联:
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
Run Code Online (Sandbox Code Playgroud)
请注意,此API 在Rails 4中已更改.在版本3和更早版本中,您只使用了该preload_associations方法.
前段时间我写了一篇关于同样问题的博客文章,其中包括其他一些巧妙的技巧(比如说你得到了正确的行为).
| 归档时间: |
|
| 查看次数: |
2059 次 |
| 最近记录: |