通过与STI的多态关联"has_many:through"关联

hol*_*eap 3 ruby model ruby-on-rails polymorphic-associations ruby-on-rails-4

我有两个使用该people表的模型:PersonPerson::Employee(继承自Person).该people表有一type列.

还有另一个模型,Group它具有多态关联,称为:owner.该groups表包含owner_id列和owner_type列.


应用程序/模型/ person.rb:

class Person < ActiveRecord::Base
    has_one :group, as: :owner
end
Run Code Online (Sandbox Code Playgroud)

应用程序/模型/人/ employee.rb:

class Person::Employee < Person
end
Run Code Online (Sandbox Code Playgroud)

应用程序/模型/ group.rb:

class Group < ActiveRecord::Base
    belongs_to :owner, polymorphic: true
    belongs_to :supervisor
end
Run Code Online (Sandbox Code Playgroud)

问题是,当我使用以下代码创建Person :: Employee时,该owner_type列设置为不正确的值:

group = Group.create
=> #<Group id: 1, owner_id: nil, owner_type: nil ... >
group.update owner: Person::Employee.create
=> true
group
=> #<Group id: 1, owner_id: 1, owner_type: "Person" ... >
Run Code Online (Sandbox Code Playgroud)

owner_type应设置为"Person::Employee",但设置为"Person".


奇怪的是,这在调用时似乎没有引起任何问题Group#owner,但在创建如下所示的关联时确实会引起问题:

应用程序/模型/ supervisor.rb:

class Supervisor < ActiveRecord::Base
    has_many :groups
    has_many :employees, through: :groups, source: :owner, 
                         source_type: 'Person::Employee'
end
Run Code Online (Sandbox Code Playgroud)

使用这种类型的关联,调用Supervisor#employees将不会产生任何结果,因为它正在查询WHERE "groups"."owner_type" = 'People::Employees'owner_type设置为'People'.

为什么这个字段设置不正确以及可以做些什么呢?


编辑:

根据,该owner_type字段没有得到正确设置,但它是按设计工作和字段设置为名称的基础 STI模式.

问题似乎是has_many:through关联搜索Group带有owner_type模型自己名称的s 而不是基础模型的名称.

设置has_many :employees, through: :group正确查询Person::Employee条目的关联的最佳方法是什么?

Jac*_*own 5

您正在使用Rails 4,因此您可以在关联上设置范围.你的Supervisor课可能看起来像:

class Supervisor < ActiveRecord::Base
  has_many :groups
  has_many :employees, lambda {
    where(type: 'Person::Employee')
  }, through: :groups, source: :owner, source_type: 'Person'
end
Run Code Online (Sandbox Code Playgroud)

然后,您可以要求主管的员工,例如supervisor.employees,生成如下查询:

SELECT "people".* FROM "people" INNER JOIN "groups" ON "people"."id" = 
"groups"."owner_id" WHERE "people"."type" = 'Person::Employee' AND
"groups"."supervisor_id" = ? AND "groups"."owner_type" = 'Person' 
[["supervisor_id", 1]]
Run Code Online (Sandbox Code Playgroud)

这使您可以使用标准关联助手(例如build),并且比编辑2稍微简单一些.