Rails的模型自關聯

關於Rails的模型自關聯有一個非常有意思的題目,大概是這樣的:

lisa = Person.create(name:'Lisa')
tom = Person.create(name:'Tom',parent_id:lisa.id)
andy = Person.create(name:'Andy',parent_id:lisa.id)
tom.parent.name => 'Lisa'
lisa.children.map(&:name) => ['Tom','Andy']

thomas = Person.create(name: 'Thomas',parent_id: tom.id)
peter = Person.create(name:'Peter',parent_id:tom.id)
gavin = Person.create(name:'Gavin', parent_id: andy.id)
lisa.grandchildren.map(&:name) => ['Thomas','Peter','Gavin']

問如何定義Person模型來滿足以上需求?

題目考察了對模型自關聯的理解,通過審題我們可以得出以下幾點:

  • Person對象的Parent同樣是Person對象(自關聯)
  • Person對象對Parent是多對一關係
  • Person對象對Children是一對多關係
  • Person對象通過Children與GrandChildren建立了一對多關係

在不考慮GrandChildren時,不難得出模型定義如下:

class Person < ActiveRecord::Base 
  belongs_to :parent, class_name: 'Person', foreign_key: 'parent_id' 
  has_many :children, class_name: 'Person', foreign_key: 'parent_id' 
end

其中Person包含兩個自關聯關係:

  • 第一個就是非常常見的從子到父的關係,在Person對象創建時指定parent_id來指向父對象;
  • 第二個關係用來指定Person對象對應的所有子對象

接下來更近一步,我們要找到Person對象子對象的子對象,換句話說:孫子對象。
如我們上面的分析,Person對象通過Children與GrandChildren建立了一對多關係,其代碼表現爲:

has_many :grandchildren, :through => :children, :source => :children

:source選項的官方文檔說明如下:

The :source option specifies the source association name for a has_many :through association. You only need to use this option if the name of the source association cannot be automatically inferred from the association name. —— rails guide

在這裏我們通過:source選項告訴Rails在children對象上查找children關聯關係。
於是該題目完整的模型定義如下:

class Person < ActiveRecord::Base
  belongs_to :parent, class_name: 'Person', foreign_key: 'parent_id'
  has_many :children, class_name: 'Person', foreign_key: 'parent_id'
  has_many :grandchildren, :through => :children, :source => :children
end

result.png

參考:Need help to understand :source option of has_one/has_many through of Rails

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章