#relationshipモデルの作成
$ rails g model Relationship follower_id:integer following_id:integer
#20160220133958_create_relationships.rbのにインデックスとか追加
def change
create_table :relationships do |t|
t.integer :follower_id
t.integer :following_id
t.timestamps null: false
end
add_index :relationships, :follower_id
add_index :relationships, :following_id
add_index :relationships, [:follower_id, :following_id], unique: true
end
end
add_index :relationships, [:follower_id, :following_id], unique: true
これは一度フォローしたユーザーを2度フォローしてしまわないようにするための一意の設定。
#UserとRelationshipの関連付け
まず、フォローするのとフォローされるのとで能動的関係と受動的関係で分けることをする。
ここでは能動的関係をactive_relationshipと呼び、受動的関係をpassive_relationshipと呼ぶことにする。
最初にactive_relationshipの方から進めていく。
まずはuserから見たもの考える。
一人のユーザーにはたくさんのfollowerがいるからhas_many。
今度はrelationshipから見たものを考える。
followingから見てfollowingしているのはユーザー1人。
followerから見てfollowerしているのはユーザー1人。
だから、
belongs_to :following
で
belongs_to :follower
has_many :active_relationships,class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
フォローしているユーザーをfollower_idを外部キーとして特定する。
belongs_to :follower, class_name: "User"
belongs_to :following, class_name: "User"
#こうすればこれだけのメソッドが使えるようになる。
active_relationship.follower フォロワーを返す
active_relationship.following フォローしているユーザーを返す
user.active_relationships.create(following_id: user.id) userを紐付けて能動的関係を作成/登録する
user.active_relationships.create!(following_id: user.id) userを紐付けて能動的関係を作成/登録する (失敗時にエラーを出力)
user.active_relationships.build(following_id: user.id) userと紐付けた新しいRelationshipオブジェクトを返す
#フォローしているユーザー
1人のユーザーにはいくつもの「フォローする/される (多対多)」のリレーションシップがある。
なのでhas_many throughを使う。
has_many :following, through: :active_relationships, source: :following
railsはfollwingを見てrelationshipsテーブルのfollowing_idを使って対象のユーザーを取得してくる。
source:はなくても良いがわかりやすくするために書居ておいた。
実際はマジでいらない。
これでuser.followingが使えるようになる。
この関連付けにより、フォローしているユーザーを配列の様に扱えるようになった。
例えば、include?メソッドを使ってフォローしているユーザーの集合を調べてみたり、関連付けを通してオブジェクトを探しだせるようになった。
user.following.find(other_user)でフォローしているユーザーを取り出せるようになった。
#followやunfollowなどのメソッドの追加
followingで取得した集合をより簡単に取り扱うためにメソッドを作成する。
# ユーザーをフォローする
def follow(other_user)
active_relationships.create(following_id: other_user.id)
end
# ユーザーをアンフォローする
def unfollow(other_user)
active_relationships.find_by(following_id: other_user.id).destroy
end
# 現在のユーザーがフォローしてたらtrueを返す
def following?(other_user)
following.include?(other_user)
end
user.followersメソッドを作成する
これは上のuser.followingメソッドと対になるやつ。
follower_idとfollowing_idを入れ替えるだけで、フォロワーについてもユーザーのフォローのときとまったく同じ方法が使用できる。
followerなので、フォローされていると考え、受動的関係と考え、passive_relationshipと考える。
has_many :passive_relationships, class_name: "Relationship", foreign_key: "following_id", dependent: :destroy
has_many :followers, through: :passive_relationships, source: :follower
#ルーティングの設定
resources :users do
member do
get :following, :followers
end
end
following_user GET /users/:id/following(.:format) users#following
followers_user GET /users/:id/followers(.:format) users#followers
このルーティングができる。
#followerとfollowingの表示
<% @user ||= current_user %>
<div class="stats">
<a href="<%= following_user_path(@user) %>">
<strong id="following" class="stat">
<%= @user.following.count %>
</strong>
following
</a>
<a href="<%= followers_user_path(@user) %>">
<strong id="followers" class="stat">
<%= @user.followers.count %>
</strong>
followers
</a>
</div>
#follow
とfolow解除のボタンの作成
ルーティングを設定
resources :relationships, only: [:create, :destroy]
ボタンのviewはもうちょと後で書く。
その前に
#コントローラーの作成
$ rails generate controller Relationships
#メソッドの追加
def create
user = User.find(params[:following_id])
current_user.follow(user)
redirect_to user
end
def destroy
user = Relationship.find(params[:id]).following
current_user.unfollow(user)
redirect_to user
end
#ボタンのviewの追加
<%= form_for(current_user.active_relationships.build) do |f| %>
<div><%= hidden_field_tag :following_id, @user.id %></div>
<%= f.submit "Follow", class: "btn btn-primary" %>
<% end %>
あとはフォロー解除のボタンと、
followとfollowerのボタンを押した時の集合のページの作成。
順次追加