多型關聯(Polymorphic Associations)
前面講到了STI與MTI,都是實作在不同需求之下
實體表格與model之間的關係
多型關聯跟MTI有八成像,但卻依然有些不同之處
今天來為各位介紹
首先在表格的migration部分如下
create_table :animals do |t|
t.string :name
t.belongs_to :animalable, :polymorphic => true
end
migrate之後,animalable會自動生成兩個欄位Animal(id: integer, name: string, animalable_id: integer, animalable_type: string)
分別紀錄外部id與類別,需要繼承的子欄位不需要特別的設定,但是有實體table
create_table :cats do |t|
t.string :sleep
end
create_table :dogs do |t|
t.string :run
end
都跑完之後,接下來是model的部分
#animal.rb
class Animal < ActiveRecord::Base
belongs_to :animalable, :polymorphic => true
end
#dog.rb
class Dog < ActiveRecord::Base
has_one :animal, :as => :animalable
delegate :name,:name=, to: :animal
end
#cat.rb
class Cat < ActiveRecord::Base
has_one :animal, :as => :animalable
delegate :name,:name=, to: :animal
end
與STI和MTI比較不同的是,model並非繼承自Animal
而是各自屬於ActiveRecord::Base
與Animal的關係是透過has_one :animal, :as => :animalable
來定義
建立資料時,沒辦法如同MTI或STI一樣
直接使用Dog.create(name: "AAA", run: "bbb")
必須要先建立Dog實體,再建立對應的Animal,範例如下:
dog = Dog.create(run: "aaa").create_animal(name: "bbb")
會自動分別存入Dog與Animal兩個實體madel
資料結構如下:
=>#<Dog id: 2, run: "aaa">
=>#<Animal id: 2, name: "bbb", animalable_id: 2, animalable_type: "Dog">
透過model定義的delegate方法,取值與給值都可以直接由Dog取到Animal的欄位
dog = Dog.last
dog.name = "ccc"
dog.save
dog.name
=>"ccc"
#或是可以直接用update_attribute方法
dog.update_attribute(:name, "ddd")
dog.name
=>"ddd"
根據我自身專案的需求,我最後是捨棄MTI改採Polymorphic Associations
因為繼承的model都還是有自己的實體tabel,要關聯其他外部表格時不會有差錯
至於在什麼情境下要使用哪一種結構,就依照專案需求而定囉。