User/relationship associations
在實作使用者 following 和 followers 之前,我們要先建立 users 和 relationships 的關聯。一個使用者有多個「關係」(has_many),因為一個「關係」牽涉到兩個使用者,所以「關係」同時屬於(belongs_to)該名使用者和被關注的使用者。
和 Section 11.1.3 建立 microposts 一樣,我們要透過關聯建立「關係」:
user.active_relationships.build(followed_id: ...)
此時,你可能會想把類似 Section 11.1.3 的程式碼加進應用裡,但有兩處不同。
首先,在 user/microposts 關聯的例子中,我們寫成:
class User < ActiveRecord::Base
has_many :microposts
.
.
.
end
這樣寫沒問題是因為在慣例中,Rails 會去尋找跟:micoposts symbol 對應的 Micropost model。不過現在的 model 是 Relationship,如果我們想寫成:
has_many :active_relationships
那就要告訴 Rails model 的 class name:Relationship。
其次,之前在 Micropost model 我們這樣寫:
class Micropost < ActiveRecord::Base
belongs_to :user
.
.
.
end
可以這樣寫是因為 microposts table 有一個 user_id 的屬性用來指出是哪一個 user(Section 11.1.1)。這種連接兩個 table 的屬性,稱為 foreign key,當指向 User model 的 foreign key 為 user_id 時,Rails 會自動取得關聯。
預設情況下,Rails 會尋找名稱為 <class>_id 的 foreign key,其中 <class> 是 model 的小寫 class name。
現在雖然我們還是在處理 users,但識別 user 的 foreign key 變成 follower_id,所以要告訴 Rails 這個改變。
所以關於 user/relationship 的關聯如以下程式碼:
app/models/user.rb
class User < ActiveRecord::Base
has_many :microposts, dependent: :destroy
has_many :active_relationships, class_name: "Relationship",
foreign_key: "follower_id",
dependent: :destroy
.
.
.
end
因為刪除使用者也該同時刪除使用者擁有的「關係」,所以在關聯中加了 dependent: :destroy。
app/models/relationship.rb
class Relationship < ActiveRecord::Base
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
end
雖然 followed 關聯在 Section 12.1.4 才會用到,但現在先增加上去比較容易理解。
建立上述關聯後,可以得到 Table 12.1 的方法:
Table 12.1: A summary of user/active relationship association methods.
| Method | Purpose |
|---|---|
| active_relationship.follower | Returns the follower |
| active_relationship.followed | Returns the followed user |
| user.active_relationships.create(followed_id: other_user.id) | Creates an active relationship associated with user |
| user.active_relationships.create!(followed_id: other_user.id) | Creates an active relationship associated with user (exception on failure) |
| user.active_relationships.build(followed_id: other_user.id) | Returns a new Relationship object associated with user |