ActiveRecord关联的条件在has_many中相互冲突的地方?

时间:2015-04-17 16:44:24

标签: sql ruby-on-rails postgresql activerecord associations

在我的应用程序(Rails 4.2.0.rc2)中,用户可以是特定机构的学生或管理员。 :admin_institutions上的关联User通过检查联接表中的role来返回用户管理的所有机构。 :students上的关联Institution还会根据institution_users.role返回该机构中所有学生的用户。

这些关联按预期工作,因此我向:admin_students添加了一个关联User,旨在返回给定用户为管理员的所有机构的所有学生。

class InstitutionUser < ActiveRecord::Base
  belongs_to :institution
  belongs_to :user
end

class Institution < ActiveRecord::Base
  has_many :institution_users
  has_many :users, :through => :institution_users
  has_many :students, -> { where "institution_users.role = 'Student'" }, :through => :institution_users, source: :user
  ...
end

class User < ActiveRecord::Base
  has_many :institution_users
  has_many :admin_institutions, -> { where "institution_users.role = 'Admin'" }, through: :institution_users, source: :institution
  has_many :admin_students, through: :admin_institutions, source: :students
  ...
end

但是,:admin_students无效。它生成以下SQL:

  

SELECT&#34;用户&#34;。* FROM&#34;用户&#34; INNER JOIN&#34; institution_users&#34; ON&#34;用户&#34;。&#34; id&#34; =&#34; institution_users&#34;。&#34; user_id&#34; INNER JOIN&#34;机构&#34; ON&#34; institution_users&#34;。&#34; institution_id&#34; =&#34;机构&#34;。&#34; id&#34; INNER JOIN&#34; institution_users&#34; &#34; institution_users_admin_students_join&#34; ON&#34;机构&#34;。&#34; id&#34; =&#34; institution_users_admin_students_join&#34;。&#34; institution_id&#34; WHERE&#34; institution_users_admin_students_join&#34;。&#34; user_id&#34; = $ 1 AND(institution_users.role =&#39;学生&#39;)AND(institution_users.role =&#39;管理员&#39;)[[&#34; user_id&#34;,190]]

不是寻找用户是管理员并选择所有学生的所有机构,而是寻找用户同时是学生和管理员的机构,因此它返回一个空集合。

有没有办法写一个关联(而不仅仅是一个方法),它会给我我想要的结果,而不会像我这样的条件冲突?

(旁注:这是这种关联的预期行为吗?如果是这样,我真的很感激进一步了解ActiveRecord为何如此解释它。)

1 个答案:

答案 0 :(得分:1)

这可能不是答案,但可能会导致一个。

我不喜欢硬编码SQL的关联:

-> { where "institution_users.role = 'Student'" }

它们肯定至少是问题的一部分,因为ActiveRecord无法解释它们确定将INSTIT_users应用于哪个表别名。

您可以通过引用InsitutionUser模型的类方法来允许ActiveRecord具有灵活性:

def self.students
  where(role: "Student")
end

这也将InstitutionUser逻辑保存在一个地方。

然后关联成为:

has_many :students, -> {merge(InstitutionUser.students)}, :through => :institution_users, source: :user

或许可以尝试一下,看看是否可以为你排序,如果没有,它可能会让事情朝着正确的方向发展。