簡體   English   中英

通過與STI的多態關聯“has_many:through”關聯

[英]“has_many :through” association through a polymorphic association with STI

我有兩個使用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

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

class Person::Employee < Person
end

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

class Group < ActiveRecord::Base
    belongs_to :owner, polymorphic: true
    belongs_to :supervisor
end

問題是,當我使用以下代碼創建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" ... >

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

通過這種類型的關聯,調用Supervisor#employees將不會產生任何結果,因為它正在查詢WHERE "groups"."owner_type" = 'People::Employees'owner_type設置為'People'

為什么這個字段設置不正確以及可以做些什么呢?


編輯:

根據這一點owner_type字段正確設置,但它按設計工作並將字段設置為基本 STI模型的名稱。

這個問題似乎是對的has_many:通過協會為搜索Group s的一個owner_type設置為模型的自己的名字,而不是基本模型的名稱。

設置has_many :employees, through: :group的最佳方法是has_many :employees, through: :group Person::Employee正確查詢Person::Employee條目的has_many :employees, through: :group關聯?

您正在使用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

然后你可以要求一個主管的員工,比如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]]

這使您可以使用標准關聯助手(例如, build ),並且比編輯2更簡單。

我確實提出了這個解決方法,它添加了一個回調來為owner_type設置正確的值:

class Group < ActiveRecord::Base
    belongs_to :owner, polymorphic: true
    before_validation :copy_owner_type

    private

    def copy_owner_type
        self.owner_type = owner.type if owner
    end
end

但是,我不知道這是否是最好和/或最優雅的解決方案。


編輯:

在發現owner_type字段應該設置為基本STI模型之后,我想出了以下方法來通過Group模型查詢Person::Employee條目:

class Supervisor < ActiveRecord::Base
    has_many :groups

    def employees
        Person::Employee.joins(:groups).where(
            'people.type' => 'Person::Employee',
            'groups.supervisor_id' => id
        )
    end
end

但是,這似乎並沒有緩存其結果。


編輯2:

我提出了一個更優雅的解決方案,包括設置has_many:通過關聯與基本模型關聯,然后創建一個范圍來僅查詢繼承的模型。

class Person < ActiveRecord::Base
    scope :employees, -> { where type: 'Person::Employee' }
end

class Supervisor < ActiveRecord::Base
    has_many :groups
    has_many :people, through: :groups, source: :owner, source_type: 'Person'
end

有了這個,我可以打電話給Supervisor.take.people.employees

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM