October 4, 2023

Viiisit [Ruby on Rails] - Active Record Associations (上)!

#ruby on rails#active record

before_action :前言

為什麼需要關聯性?

在 Rails 中,Active Record 關聯是指不同 Model 之間的連結與關係。

我們在一個專案裡,一定不只有一個 Model,會同時存在許多 Model,
在 Rails 裡,我們可以透過關聯將這些 Model 連結在一起,大致上歸納出以下優點:

Model 需要關聯性是為了更好地組織和管理資料,以及實現資料間的關聯和連結。

關聯種類

這種關聯性可以在資料庫層面建立表格之間的連結,使得資料之間可以相互關聯和互動,
進而簡化資料的查詢和操作。

Rails 支援以下六種關聯:

透過關聯而產生的方法,你可以在 Model 類別中指定關聯的類別和條件,Rails 將根據這些定義在資料庫層面建立對應的關聯。


一對一關聯


一對多關聯


多對多關聯

在 Rails 中,有兩種方式可以實現多對多關聯:
has_many :throughhas_and_belongs_to_many

has_many :through

has_many :through 通常在以下情況下使用:

  1. 需要跟蹤關聯的其他資料:當你需要在多對多關聯中存儲其他資料時,例如時間戳、評分、評論等,has_many :through 是更好的選擇。
  2. 複雜查詢需求:如果你需要執行複雜的查詢,例如過濾、排序或計數,has_many :through 允許你使用 Active Record 查詢方法對中間模型進行操作,進而實現更高級的查詢。
  3. 未來擴展性:當你希望你的數據模型具有未來擴展性,以便在以後添加更多的關聯或屬性時,has_many :through 更靈活。

使用 has_many :through

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# User 模型
class User < ApplicationRecord
has_many :user_roles
has_many :roles, through: :user_roles
end

# Role 模型
class Role < ApplicationRecord
has_many :user_roles
has_many :users, through: :user_roles
end

# UserRole 模型作為中間模型
class UserRole < ApplicationRecord
belongs_to :user
belongs_to :role
end

has_and_belongs_to_many

has_and_belongs_to_many 關聯是一種簡單的多對多關聯,
不使用中間模型,只需一個連接表(join table)來維護關聯,通常在以下情況下使用:

  1. 簡單多對多關聯:當多對多關聯相對簡單,不需要額外的資料(例如,評論或時間戳)時,has_and_belongs_to_many 可以更容易地設置和使用。
  2. 不需要進行複雜的查詢:如果你只需要基本的查詢(例如,獲取所有關聯記錄),並且不需要進行複雜的過濾或排序,那麼 has_and_belongs_to_many 可能是更簡單的選擇。

使用 has_and_belongs_to_many

1
2
3
4
5
6
7
8
9
# User 模型
class User < ApplicationRecord
has_and_belongs_to_many :roles
end

# Role 模型
class Role < ApplicationRecord
has_and_belongs_to_many :users
end

簡單來說,如果需要將關聯模型視為獨立的實體來操作,
那麼應該設置一個 has_many :through 關聯。
如果不需要對關聯模型進行任何操作,
也許設置一個 has_and_belongs_to_many 關聯會更簡單(需要記住在資料庫中創建連接表 join table)。
如果你需要在關聯模型上進行驗證、回調或使用額外的屬性,應該使用 has_many :through


我們今天先到這!下篇繼續提及 Active Record Associations 的相關概念!

參考資料:
為你自己學 Ruby on Rails - Model
Active Record Associations
PJCHENder - [Rails] Active Record Association (Model)