上回我們講到 Active Record Association 的基礎觀念,今天繼續延伸下去!
多型關聯(Polymorphic Association)是一種在資料庫中建立關聯的方法,允許一個模型與多個其他模型建立關聯,並且可以根據需要動態指向這些模型中的一個。主要目的是在不知道或不確定關聯到哪個模型的情況下實現關聯。
想像你正在建立一個簡單的網站,用戶可以發表評論(Comments),但這些評論可以關聯到多種不同類型的內容,例如文章(Articles)和圖片(Photos)。這時就可以使用多型關聯。
建立一個 Comment
模型,該模型將關聯到多種不同類型的內容。
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
建立其他模型,例如 Article
和 Photo
,並將它們與 Comment
進行多型關聯。
class Article < ApplicationRecord
has_many :comments, as: :commentable
end
class Photo < ApplicationRecord
has_many :comments, as: :commentable
end
我們就可以在 Comment
模型中使用 commentable
來關聯到不同類型的內容。
例如,當用戶發表一個評論時:
# 建立一個評論關聯到一篇文章
article = Article.find(1)
comment = article.comments.create(content: '這是一個評論')
# 建立一個評論關聯到一張圖片
photo = Photo.find(2)
comment = photo.comments.create(content: '這是另一個評論')
可以通過 commentable
關聯動態地關聯到不同類型的內容,同時保持代碼的簡單性和可擴展性。
自連接(Self-joining)關聯是一種在資料庫中建立關聯的技術,其中同一個表格(或模型)中的記錄可以與該表格中的其他記錄建立關聯。換句話說,就是在一個模型中創建一個與自己相關聯的關聯,通常用於處理與模型自身相關的數據。
例如,有一個 "Employee" 的模型,每個員工都有一個直接上級(即另一個員工),並且他們都屬於同一個公司。
可以使用自連接來建立員工之間的關聯,同時維護每個員工的直接上級。
# Employee 模型
class Employee < ApplicationRecord
belongs_to :manager, class_name: 'Employee', optional: true
has_many :subordinates, class_name: 'Employee', foreign_key: 'manager_id'
end
這個模型有兩個關聯:
belongs_to :manager
:這個關聯表示每個員工都屬於另一個員工,並且 class_name
參數指定了關聯的模型是自身的 "Employee" 模型。意即,每個員工都有一個直接上級,但不是每個員工都必須有一個直接上級(所以我們使用 optional: true
)。
has_many :subordinates
:這個關聯表示每個員工都可以擁有多個下屬,同樣,我們使用 class_name
和 foreign_key
參數指定了關聯的模型和外鍵字段。
使用這些關聯來建立員工之間的關係:
# 建立員工記錄
manager = Employee.create(name: 'Manager')
employee1 = Employee.create(name: 'Employee 1', manager: manager)
employee2 = Employee.create(name: 'Employee 2', manager: manager)
# 查詢員工的直接上級和下屬
puts employee1.manager.name # 輸出 "Manager"
puts manager.subordinates.pluck(:name) # 輸出 ["Employee 1", "Employee 2"]
這樣,你可以使用自連接來建立模型內部的層次結構關係,這在處理組織結構、層次性數據或任何需要記錄與自身建立關聯的情況下非常有用。自連接使用相同的模型在內部建立關聯,同時保持代碼的簡潔性和可讀性。
在 Rails Guide - Active Record Association 中,有提及關於在 Rails 應用程式中有效使用 Active Record Association 的注意事項:
控制緩存(Controlling caching):
Active Record 通常會對關聯數據進行緩存,以提高性能。
一些查詢結果可能會被緩存在記憶體中,但有時這可能導致意外的行為。
可以使用 reload
方法來重新加載關聯數據,以確保獲取的是最新的數據。
避免名稱衝突(Avoiding name collisions):
在模型中定義多個關聯時,要注意避免名稱衝突!
如果多個關聯使用相同的名稱,可能會導致混淆和錯誤。
為每個關聯選擇具有描述性的名稱,並使用 :class_name
選項來指定模型的名稱,以避免混淆。
更新模式(Updating the schema):
更改模型之間的關聯時,記得更新 schema!
如果新增、刪除或修改關聯,需要遷移(migration)來更新資料庫結構,以反映新的關聯。
控制關聯範圍(Controlling association scope):
使用 has_many
或 has_one
關聯時,可以使用 :scope
選項來定義範圍,以限制關聯中的數據。這對於過濾或排序關聯數據非常有用。
雙向關聯(Bi-directional associations):
有時可能需要在兩個模型之間建立雙向關聯,也就是說,當一個模型關聯到另一個模型時,也希望反向的關聯也存在。這可以通過在兩個模型中分別定義關聯來實現。確保處理好雙向關聯可以更方便地訪問和操作數據。
參考資料:
文章同步於個人部落格:Viiisit!(歡迎參觀 ୧ʕ•̀ᴥ•́ʔ୨)