before_action :前言
為什麼需要關聯性?
在 Rails 中,Active Record 關聯是指不同 Model 之間的連結與關係。
我們在一個專案裡,一定不只有一個 Model,會同時存在許多 Model,
在 Rails 裡,我們可以透過關聯將這些 Model 連結在一起,大致上歸納出以下優點:
Model 需要關聯性是為了更好地組織和管理資料,以及實現資料間的關聯和連結。
資料的結構化:通常一個應用程式涉及多個資料,彼此之間可能存在著很複雜的關係。
可以將這些資料的關係結構化,使得資料庫中的資料更容易理解和管理。整合資料:資料往往存在著相互關聯的情況。例如:一個使用者有多個訂單。
可以將這些相關聯的資料整合在一起,使得查詢和操作資料更加方便。簡化資料存取:在查詢資料時不需要手動撰寫複雜的 SQL 語句,而是使用 Rails 提供的簡單方法即可。這樣可以節省開發時間,並減少出錯的可能性。
維護性和擴展性:當應用程式需要新增新的資料實體或調整資料結構時,使用 Model 的關聯性可以輕鬆地進行修改而不影響其他部分的程式碼。
關聯種類
這種關聯性可以在資料庫層面建立表格之間的連結,使得資料之間可以相互關聯和互動,
進而簡化資料的查詢和操作。
Rails 支援以下六種關聯:
- belongs_to
- has_one
- has_many
- has_many :through
- has_one :through
- has_and_belongs_to_many
透過關聯而產生的方法,你可以在 Model 類別中指定關聯的類別和條件,Rails 將根據這些定義在資料庫層面建立對應的關聯。
一對一關聯
belongs_to
生成 Profile Model 的指令:rails generate model Profile bio:text user:belongs_to
(or)rails generate model Profile bio:text user:references
–> 這樣就會在 Profile 資料表中生成user_id
這個 foreign key- 例如,個人檔案只屬於一位使用者。
1
2
3
4# Profile 模型
class Profile < ApplicationRecord
belongs_to :user
endhas_one
生成 User Model 的指令:rails generate model User name:string
- 例如,一個使用者只有一個個人檔案。
1
2
3
4# User 模型
class User < ApplicationRecord
has_one :profile
end當有
has_one :profile
時,這個關聯會生成以下方法:
1
2
3
4
5
6profile -> user.profile # 找出用戶的個人檔案
profile= -> user.profile = profile # 將一個現有的個人檔案分配給用戶,以更改用戶的個人檔案。
build_profile -> user.build_profile(bio: 'About me') # 建立一個新個人檔案,但該個人檔案不會立即保存到資料庫中。
create_profile -> user.create_profile(bio: 'About me') # 建立一個新個人檔案,同時個人檔案會保存到資料庫中。
create_profile! -> user.create_profile!(bio: 'About me') # 當保存個人檔案時,如果存在驗證失敗或其他錯誤,將引發異常(exception),而非返回 false。
reload_profile -> user.reload_profile # 如果你修改了個人檔案,但希望獲取最新的數據,可以使用 reload_profile 方法。has_one :through(透過一對一關聯):
生成 User Model 的指令:rails generate model User name:string
生成 Profile Model 的指令:rails generate model Profile bio:text
生成 Account Model 的指令:rails generate model Account user:references
–> 這樣就會在 Account 資料表中生成user_id
這個 foreign key- 例如,一個使用者可以透過一個帳戶來存取其餘的資訊。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16# User 模型
class User < ApplicationRecord
has_one :account
has_one :profile, through: :account
end
# Account 模型
class Account < ApplicationRecord
belongs_to :user
has_one :profile
end
# Profile 模型
class Profile < ApplicationRecord
belongs_to :account
end可以使用以下方法來建立與尋找關聯資料:
1
2
3
4
5
6
7
8
9
10
11# 建立使用者
user = User.create(name: 'Viii')
# 建立帳戶,並與使用者建立關聯
account = user.create_account
# 建立個人檔案,並與帳戶建立關聯
profile = account.build_profile(bio: 'About me')
# 保存關聯記錄到資料庫
user.save查找:
1
2
3
4
5
6
7
8
9
10
11# 查找使用者的帳戶
account = user.account
# 查找使用者的個人檔案(透過帳戶關聯)
profile = user.profile
# 查找帳戶所屬的使用者
account_user = account.user
# 查找帳戶關聯的個人檔案
account_profile = account.profile
一對多關聯
has_many
- 例如,一個使用者有多篇文章。
1
2
3
4
5
6
7
8
9# User 模型
class User < ApplicationRecord
has_many :articles
end
# Article 模型
class Article < ApplicationRecord
belongs_to :user
end當有
has_many :articles
時,這個關聯會自帶以下方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17articles -> user.articles # 獲取該用戶的所有文章
articles<<(object, ...) -> user.articles << article1 # 來將一篇文章添加到用戶的文章集合中
articles.delete(object, ...) -> user.articles.delete(article1) # 來刪除用戶的某篇文章
articles.destroy(object, ...) -> user.articles.destroy(article1) # 來刪除用戶的某篇文章,同時也會刪除該文章的資料庫記錄
articles=(objects) -> user.articles = [article1, article2] # 來設定用戶的所有文章
article_ids -> user.article_ids # 來獲取用戶的所有文章的 ID
article_ids=(ids) -> user.article_ids = [1, 2, 3] # 來設定用戶的所有文章的 ID
articles.clear -> articles.clear # 用於從關聯集合中刪除所有 Article 物件,但不會銷毀這些對象。
articles.empty? -> articles.empty? # 用於檢查關聯集合是否為空,如果集合中不包含任何 Article 物件,則返回 true。
articles.size -> articles.size # 用於獲取關聯集合中的 Article 物件數量。
articles.find(...) -> articles.find # 用於查找關聯集合中滿足指定條件的 Article,使用 id 來查找文章。
articles.where(...) -> articles.where # 用於使用條件查找關聯集合中的 Article,並返回一個 ActiveRecord 查詢。
articles.exists?(...) -> articles.exists? # 用於檢查關聯集合中是否存在滿足指定條件的 Article,如果存在則返回 true,否則返回 false。
articles.build(attributes = {}, ...) -> articles.build # 用於建立一個新的 Article,但不會將其保存到資料庫中。可以選擇性地提供屬性(attributes)作為參數,以自定義新建對象的屬性。
articles.create(attributes = {}) -> articles.create # 用於建立一個新的 Article 並將其保存到資料庫中。可以選擇性地提供屬性(attributes)作為參數,以自定義新建對象的屬性。
articles.create!(attributes = {}) -> articles.create! 方法與 articles.create 方法相似,但當保存文章時,如果存在驗
articles.reload -> articles.reload # 用於重新向數據庫發出查詢,以確保關聯集合的數據是最新的。
多對多關聯
在 Rails 中,有兩種方式可以實現多對多關聯:
has_many :through 和 has_and_belongs_to_many。
has_many :through
has_many :through
通常在以下情況下使用:
- 需要跟蹤關聯的其他資料:當你需要在多對多關聯中存儲其他資料時,例如時間戳、評分、評論等,
has_many :through
是更好的選擇。 - 複雜查詢需求:如果你需要執行複雜的查詢,例如過濾、排序或計數,
has_many :through
允許你使用 Active Record 查詢方法對中間模型進行操作,進而實現更高級的查詢。 - 未來擴展性:當你希望你的數據模型具有未來擴展性,以便在以後添加更多的關聯或屬性時,
has_many :through
更靈活。
使用 has_many :through
:
1 | # User 模型 |
has_and_belongs_to_many
has_and_belongs_to_many
關聯是一種簡單的多對多關聯,
不使用中間模型,只需一個連接表(join table)來維護關聯,通常在以下情況下使用:
- 簡單多對多關聯:當多對多關聯相對簡單,不需要額外的資料(例如,評論或時間戳)時,
has_and_belongs_to_many
可以更容易地設置和使用。 - 不需要進行複雜的查詢:如果你只需要基本的查詢(例如,獲取所有關聯記錄),並且不需要進行複雜的過濾或排序,那麼
has_and_belongs_to_many
可能是更簡單的選擇。
使用 has_and_belongs_to_many
:
1 | # User 模型 |
簡單來說,如果需要將關聯模型視為獨立的實體來操作,
那麼應該設置一個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)