【问题标题】:Retrieving rows from one table with polymorphic associations从具有多态关联的一个表中检索行
【发布时间】:2011-11-02 00:10:17
【问题描述】:

我有一个模型与其他三个表具有多态关联:

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)

它打破了轨道,因为 User.find(...) 返回一个 Array 并且没有为该类定义 where 方法。

我尝试了其他一些选项,但没有找到实现我想要的方法。你能帮助我吗?谢谢!

【问题讨论】:

标签: ruby-on-rails ruby activerecord join polymorphic-associations


【解决方案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 = ...")

我实际上并没有尝试过,而是多态关联。向模型添加 2 列:xxx_typexxx_id。他们用于处理 assoc。有多个模型。

【讨论】:

  • 感谢您的回答。你提议的没有奏效。它没有返回任何行。我已经更新了我的问题,以便更容易理解
  • 所以,我已经阅读了您的帖子。你试过吗?:User.include(:authenticatable).where(:school_id =&gt; some_value) thisshould return ActiveRelation object 然后你可以调用.all ro 任何可枚举的方法。请让我知道它是否有帮助
  • User.include(:authenticatable).where(:school_id =&gt; some_value) 给我以下错误:NoMethodError: private method 'include' called for #&lt;Class:0x00000106c2a5b8&gt; 我尝试使用includes(复数)。它是这样说的:Mysql2::Error: Unknown column 'users.school_id' in 'where clause':...
  • 是的,真的includes :),只是我的错字。所以你走对了。用户表中有 school_id 列吗?
  • 我再次更新了我的问题,提供了有关模型的更多信息。要回答您的问题,不,用户没有school_id 列。请记住,我要检索具有特定 authenticatable school id 的所有用户。 school_id 列存在于其他模型(员工、监护人和学生)中,但不存在于用户中。用户只是与他们有一个多态关联。
【解决方案2】:

您可以使用子查询来解决问题,也许可以得到一些工作:

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)

我发现在许多情况下,多态关系比它们的价值更麻烦,因为执行查询和批量更新等操作非常困难,并且无法使用外键约束。稍加思考,通常会有一个合理的数据模型在没有它们的情况下运行良好。

【讨论】:

    猜你喜欢
    • 2017-09-08
    • 2021-11-22
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 2021-06-01
    • 2022-01-20
    • 1970-01-01
    相关资源
    最近更新 更多