3

我有兩個使用people表的模型:PersonPerson::Employee(它繼承自Person)。 people表具有type列。「has_many:through」通過與STI的多態關聯關聯

還有另一個模型,Group,它有一個多態關聯稱爲:ownergroups表具有owner_id列和owner_type列。


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

class Person < ActiveRecord::Base 
    has_one :group, as: :owner 
end 

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

class Person::Employee < Person 
end 

應用程序/模型/組。 rb:

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

的問題是,當我創建了一個Person ::員工用下面的代碼中,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'

爲什麼此字段設置不正確,可以做些什麼?


編輯:

this,該owner_type越來越設置不正確,但它是按設計工作和字段設置爲基地 STI模型的名稱。

這個問題似乎是在的has_many:通過協會Group s的一組owner_type與模型的自己名稱搜索,而不是基地模型的名字。

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

回答

4

您正在使用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更直接。

+0

謝謝,我不知道'has_many'可以採取Proc。 – hololeap

0

我也想出了此解決方案,增加了一個回調來設置正確的值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模型後,我想出了下面的方法來查詢Person::Employee條目通過Group型號:

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

+0

您測試了嗎?有'人'實際上導致任何問題? – BroiSatse

+0

我澄清了我的問題,但是在做has_many:through關係指向'belongs_to:owner'關係時出現問題。我_已測試過這段代碼,目前看起來效果不錯。 – hololeap

+0

好的,我問這是因爲這個問題,這基本上與你所做的相反:http://stackoverflow.com/questions/9628610/why-polymorphic-association-doesnt-work-for-sti-if-多態的類型列 – BroiSatse