ActiveRecord has_many :through 關聯

Published on:

在 Rails 中 Model 常常使用到一對多的關係,像是一台車有四個輪子,但每個輪子都只屬於一台車

我們會用 has_manybelongs_to 來定義 Model 之間的關係,在 Tire 的資料表需要有 car_id 欄位來儲存所屬車子的 ID。

class Car
  has_many :tires
end

class Tire
  belongs_to :car
end

而多對多的關係就會用到 has_many :through,取個例子:在學校裡,一個社團可以有多名成員,每位成員也可以參加多個社團,這樣的關係就是「多對多關係」。

# 一個社團可以有多名成員
group
|-- member
|-- member
`-- member

# 每位成員可以參加多個社團
member
|-- group
|-- group
`-- group

我們無法只靠兩張表來表現多對多的關係,所以這時候需要再新增一個 Model,透過(:through)這一個 Model 來建立多得多的關係。

# group1 的成員有 member1, member2, member3
# group2 的成員有 member3
# group3 的成員有 member3

group1 -- group_member -- member1
       |- group_member -- member2
       |
       `- group_member -- member3
                        |
group2 -- group_member -|
group3 -- group_member -'

# 反過來說
# member1 參加了 group1
# member2 參加了 group1
# member3 參加了 group1, group2, group3

以上圖為例,Model 定義如下:

class Group
  has_many :group_members
  has_many :members, through: :group_members
end

class GroupMember
  belongs_to :group
  belongs_to :members
end

class Member
  has_many :group_members
  has_many :groups, through: :group_members
end

GroupMember 要先與 GroupMember 建立好一對多的關係,才能透過 GroupMember 建立彼此多對多的關係。

在這邊可以看到 GroupMember 對於其他兩個 Model 的關聯是用 belongs_to 來定義,所以要記得在資料表中建立 group_idmember_id 欄位。

參考指令:

rails g migration CreateGroup name:string
rails g migration CreateGroupMember group_id:integer member_id:integer
rails g migration CreateMember name:string

參考資料

Rails102
Rails Guide

Comments

comments powered by Disqus