用Relationship model 來當中介可以簡化結構
$ rails generate model Relationship follower_id:integer followed_id:integer
Because we will be finding relationships by follower_id and by followed_id, we should add an index on each column for efficiency, as shown in Listing 12.1.
add_index :relationships, [:follower_id, :followed_id], unique: true這行可以避免user重覆跟隨另一個user
Listing 12.1 also includes a multiple-key index that enforces uniqueness on (follower_id, followed_id) pairs, so that a user can’t follow another user more than once. (Compare to the email uniqueness index from Listing 6.28 and the multiple-key index in Listing 11.1.) As we’ll see starting in Section 12.1.4, our user interface won’t allow this to happen, but adding a unique index arranges to raise an error if a user tries to create duplicate relationships anyway (for example, by using a command-line tool such as curl).
Rails would see “followeds” and use the singular “followed”, assembling a collection using the followed_id in the relationships table. But, as noted in Section 12.1.1, user.followeds is rather awkward, so we’ll write user.following instead.
Naturally, Rails allows us to override the default, in this case using the source parameter (as shown in Listing 12.8), which explicitly tells Rails that the source of the following array is the set of followed ids.
Rails would see “followeds” and use the singular “followed”, assembling a collection using the followed_id in the relationships table. But, as noted in Section 12.1.1, user.followeds is rather awkward, so we’ll write user.following instead. Naturally, Rails allows us to override the default, in this case using the source parameter (as shown in Listing 12.8), which explicitly tells Rails that the source of the following array is the set of followed ids.
Follows a user.
Unfollows a user.
Returns true if the current user is following the other user.
user.following => 會利用follower_id這個foreign key，去找active_relationships的followed_id (用source告知) (會利用follower_id：跟隨者有幾個被跟隨者)
Figure 12.7: A model of followed users through active relationships.
user.followers => 會利用followed_id這個foreign key，去找passive_relationships的follower_id (用source告知) (會利用followed_id：被跟隨的這個人有幾個跟隨者)
Figure 12.9: A model for user followers through passive relationships.
You might suspect that the URLs for following and followers will look like /users/1/following and /users/1/followers, and that is exactly what the code in Listing 12.15 arranges. Since both pages will be showing data, the proper HTTP verb is a GET request, so we use the get method to arrange for the URLs to respond appropriately. Meanwhile, the member method arranges for the routes to respond to URLs containing the user id. The other possibility, collection, works without the id, so that /users/tigers
would respond to the URL /users/tigers (presumably to display all the tigers in our application).
As in that case, Rails calculates the count directly in the database for efficiency.
註：member寫好會變這樣，網址會是：/users/1/following和/users/1/followers但要記得回去Controller寫Action/Method = following跟followers
HTTP request URL Action Named route
GET /users/1/following following following_user_path(1)
GET /users/1/followers followers followers_user_path(1)
subselect 子查詢 Micropost.where("user_id IN (?) OR user_id = ?", following_ids, id) Micropost.where("user_id IN (:following_ids) OR user_id = :user_id",
following_ids: following_ids, user_id: id) following_ids = "SELECT followed_id FROM relationships
WHERE follower_id = :user_id"
大概是這個樣子： SELECT * FROM microposts
WHERE user_id IN (SELECT followed_id FROM relationships
WHERE follower_id = 1)
OR user_id = 1