Followed users
現在就要來處理 Relationship 關聯:following 和 followers。
這是我們首次使用 has_many :throuth:一個使用者透過 relationships 可以 following 多名使用者。
預設行為中,使用 has_many :throuth,Rails 會去尋找和關聯名稱單數形式相對應的 foreign key,換句話說,程式碼會像這樣:
has_many :followeds, through: :active_relationships
Rails 會發現關聯名稱是「followeds」,然後使用單數形式「followed」,因此會在 relationships table 中獲得一組 followed_id 組成的集合。
但是之前提過,「user.followeds」是很怪的語法,所以我們會使用「user.following」取代。
基本上,Rails 允許我們覆蓋預設設定,在這個例子中,可以使用 source 參數(如 Listing 12.8 所示)告訴 Rails,「嘿, following 陣列是由 followed_id 組成的」。
Listing 12.8: 在 User model 中增加 following 關聯設定
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
has_many :following, through: :active_relationships, source: :followed
.
.
.
end
Listing 12.8 的關聯設定可以讓我們充分利用 Active Record 和陣列的功能。例如,可以使用 include? 方法檢查使用者關注的對象有沒有某個使用者,或是透過關聯查詢某個使用者:
user.following.include?(other_user)
user.following.find(other_user)
在很多情況下,我們可以把 following 當成陣列使用,Rails 會很聰明的知道如何有效率的處理,例如以下的程式碼:
following.include?(other_user)
看起來好像是先把關注的使用者全部從資料庫裡找出來,再調用 include? 方法,但其實為了提高效率,Rails 會直接在資料庫層直接執行相關的操作。和之前在 Section 11.2.1 一樣,使用 user.microposts.count,都是直接在資料庫裡操作。
為了處理關注使用者的操作,我們要定義兩種輔助方法:follow 和 unfollow。這樣我們就可以寫出例如,user.follow(other_user)。接著還要定義 following? 布林值方法,用來檢查一名使用者是否關注了另一名使用者。
目前的情況,正好適合拿來先寫測試,因為我們還要好一陣子才會開始開發網站介面,這期間我們如果只專注在開發層面的應用程式碼,到時候在客戶端發現問題就比較難處理了。
在這個例子中,可以先為 User model 寫個簡短的測試:
- 使用
following?方法來確保某個使用者沒有關注另一名使用者 - 再用
follow方法去關注另一名使用者 - 接著再用
following?方法確認關注有成功 - 最後使用
unfollow方法解除關注,並確認操作有成功
測試程式碼如 Listing 12.9 所示:
Listing 12.9: 測試關注使用者的幾個功能 Red
test/models/user_test.rb
require 'test_helper'
class UserTest < ActiveSupport::TestCase
.
.
.
test "should follow and unfollow a user" do
michael = users(:michael)
archer = users(:archer)
assert_not michael.following?(archer)
michael.follow(archer)
assert michael.following?(archer)
michael.unfollow(archer)
assert_not michael.following?(archer)
end
end
參考 Table 12.1,我們可以使用 following 關聯定義 follow、unfollow 和 following?,如 Listing 12.10 所示(注意,只要可能,就會省略 self 變數):
Listing 12.10: 定義輔助方法 for 關注使用者
app/models/user.rb
class User < ActiveRecord::Base
.
.
.
def feed
.
.
.
end
# Follows a user.
def follow(other_user)
active_relationships.create(followed_id: other_user.id)
end
# Unfollows a user.
def unfollow(other_user)
active_relationships.find_by(followed_id: other_user.id).destroy
end
# Returns true if the current user is following the other user.
def following?(other_user)
following.include?(other_user)
end
private
.
.
.
end
現在執行測試,應該會通過:
Listing 12.11: Green
$ bundle exec rake test