iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 4
0
Modern Web

Ruby礦工的Rails地圖系列 第 4

STI , MTI 與多型關聯(Polymorphic Associations) 系列三

多型關聯(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,要關聯其他外部表格時不會有差錯

至於在什麼情境下要使用哪一種結構,就依照專案需求而定囉。


上一篇
STI , MTI 與多型關聯(Polymorphic Associations) 系列二
下一篇
如何自行編寫Ruby的方法
系列文
Ruby礦工的Rails地圖30

尚未有邦友留言

立即登入留言