我有一个模型与其他三个表有多态关联:
class User < ActiveRecord::Base
belongs_to :authenticatable, :polymorphic => true
# == Schema Information
#
# Table name: employees
#
# id :integer(4) not null, primary key
# ...
# school_id :integer(4)
class Guardian < ActiveRecord::Base
has_one :user, :as => :authenticatable
belongs_to :school
# == Schema Information
#
# Table name: guardians
#
# id :integer(4) not null, primary key
# ...
# school_id :integer(4)
class Guardian < ActiveRecord::Base
has_one :user, :as => :authenticatable
belongs_to :school
# == Schema Information
#
# Table name: students
#
# id :integer(4) not null, primary key
# ...
# school_id :integer(4)
class Student < ActiveRecord::Base
has_one :user, :as => :authenticatable
belongs_to :school
如您所见,最后3个模型属于“学校”模型,因此有一个名为school_id
的列。我想从user
检索所有行,使其对应的可验证的school_id等于某个值。为了澄清,我想做这样的事情:
User.joins(:authenticatable).where(:school_id => some_value)
实际上,这将导致
ActiveRecord::EagerLoadPolymorphicError
最后一点,我设法查找了一些文档,这些文档表明在多态关联中使用include应该有效,例如:
User.find(:all, :include => :authenticatable) (This works)
但是,如果我这样做:
User.find(:all, :include => :authenticatable).where(:school_id => some_value)
它会破坏rails,因为User.find(...)
返回Array
并且没有为该类定义where方法。
我已经尝试了其他一些选择,并没有找到实现我想要的方法。你能帮助我吗?谢谢!
答案 0 :(得分:1)
您可以尝试使用joins
语句中的SQL查询来解决它:
Model1.joins("INNER JOIN model2 ON model2.id = model1.polymorphizm_id INNER JOIN model3 ON model3.id = model1.polymorphizm_id INNER JOIN model4 ON model4.id = model1.polymorphizm_id").where("model2.column_id = ... or model3.column_id = ... or model4.column_id = ...")
我实际上并没有尝试过,而是polimorphic assoc。为模型添加了2列:xxx_type
和xxx_id
。他们用来处理assoc。有多种型号。
答案 1 :(得分:0)
你可以通过子查询来获得好处,也许可以得到一些有用的东西:
User.where(authenticable: Guardian.where(school_id: some_value))
如果您正在使用Rails 5,他们会将.or
添加到ActiveRecord
,因此您可以像以下一样加入其中:
User.where(authenticable: Guardian.where(school_id: some_value))
.or.where(authenticable: Student.where(school_id: some_value))
merge
是另一种可能产生一些结果的方法:
User.all.merge(Guardian.where(school_id: some_value))
我不太熟悉查询多态表,因此您的里程可能会因上述情况而有所不同。最糟糕的情况是,您最终可能需要执行多个查询来保留范围:
user_ids = Guardian.joins(:user).select('users.id').where(school_id: some_value).pluck(:user_id) +
Student.joins(:user).select('users.id').where(school_id: some_value).pluck(:user_id)
users = User.where(id: user_ids)
您现在可能会遇到架构,但如果您可以随意更改它,看起来您可能会更好地使用单表继承关系:
class User < ActiveRecord::Base
belongs_to :school
end
class Student < User
end
class Guardian < User
end
然后你只需说:
User.where(school_id: some_value)
我发现多态关系比它们在很多情况下的价值更加麻烦,因为查询和批量更新这样的事情是多么困难,以及无法使用外键限制。通过一些额外的思考,通常情况下合理的数据模型在没有它们的情况下运行良好。