🐣
[Ruby on Rails] フォローフォロワー機能の作成
テーブルの設計
カラム名 | データ型 | カラムの説明 |
---|---|---|
follower_id | integer | フォローするユーザーのid |
followed_id | integer | フォローされるユーザーのid |
フォロー機能の場合、フォローするのもフォローされるのも user であるため、
少なくとも片方は user_id 以外にする必要があります
なので、わかりやすいよう名前をつけています
モデルの作成
$ rails g model Relationship follower_id:integer followed_id:integer
モデルとテーブルを作成したら必ず マイグレートする
$ rails db:migrate
モデルの関連付けを行う
ここで今までと同じように
relationship.rb
belongs_to :follower
belongs_to :user
としてしまうと、
- followersテーブルを参照しにいってしまうため、エラーになってしまいます。
- user にした場合、どっちがどっちのuserかわからなくなってしまいます
そこで、次のように クラス名(モデル名)を指定してあげます
relationship.rb
belongs_to :follower, class_name: "User"
belongs_to :followed, class_name: "User"
- class_name とは、関連名のモデル名を指定するオプションです
- 関連付けの相手のオブジェクト名を関連付け名から生成できない場合に使用します
user.rb
has_many :followers, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy
has_many :followeds, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy
has_many :following_users, through: :followers, source: :followed
has_many :follower_users, through: :followeds, source: :follower
解説
- フォロー/フォロワー機能だけなら、最初の1行だけでいいですが、一覧機能を作成するために4行書いています
- 中間テーブルを使用するため、仮のテーブル名を使用し、つなげています
word
- class_name とは、関連名のモデルを指定するオプションです
- foreign_key 参照先を参照するための外部キー(カラム名)を指定するもの
- soruce 多対多の関連先のモデル名を指定するオプション
- throurh 経由してと言う意味で、 今回は後ろのテーブルを経由しています
メソッドの作成
モデルにこの後使用するメソッドを作成していきます
user.rb
def follow(user_id)
followers.create(followed_id: user_id)
end
def unfollow(user_id)
followers.find_by(followed_id: user_id).destroy
end
def following?(user)
following_users.include?(user)
end
解説
follow
- createメソッドは因数に渡されたデータを元にモデルのインスタンスを作成して、データベースに保存するメソッドです
-
モデル名.create(カラム名: 値)
として使用します
unfollow
- find_by メソッドは()の中の条件に合う最初のレコードを一つだけ返すメソッドです。
- destroy メソッドはすでにテーブル上に存在するレコードを削除するメソッドです
following?
- include? メソッドは引数で指定した要素が、配列に含まれているか判断するメソッドです
- 含まれていれば true いなければ false を返します
ルーティングの設定
routes.rb
resources :users, only: [:index,:show,:edit,:update] do
member do
get :follows, :followers
end
resource :relationships, only: [:create, :destroy]
end
- member は resources で生成されるルートに、決められたルート以外を追加するための処理で、resourcesの do end の中で使用します
- リンクに :id をつけない場合は collection を使用します
コントローラー 作成
$ rails g controller relationships
relationships_controller
def create
current_user.follow(params[:user_id])
redirect_to request.referer
end
def destroy
current_user.unfollow(params[:user_id])
redirect_to request.referer
end
- 先ほどモデルで定義したメソッドを使用します
users_controller
def show
@user = User.find(params[:id])
@following_users = @user.following_users
@follower_users = @user.follower_users
end
メモ
- Userモデルから id をもらいます
- following_user はテーブル名です
- follower_user はテーブル名です
Users/show の view画面
今回は部分テンプレートに フォロー/フォロワー数/フォローボタンを表示させます
<table>
<tr>
<th>follows</th>
<th>
<%= link_to follows_user_path(user) do %>
<%= user.followers.count %>
<% end %>
</th>
</tr>
<tr>
<th>followers</th>
<th>
<%= link_to followers_user_path(user) do %>
<%= user.followeds.count %>
<% end %>
</th>
</tr>
<tr>
<td>
<% if current_user != user %>
<% if current_user.following?(user) %>
<%= link_to "フォロー外す", user_relationships_path(user.id), method: :delete, class: "btn btn-danger" %>
<% else %>
<%= link_to "フォローする", user_relationships_path(user.id), method: :post, class: "btn btn-success" %>
<% end %>
<% end %>
</td>
</tr>
</table>
解説
フォロー/フォロワー数
- 今回は <table></table> タグを使用しています
- link_to メソッドを使用して、リンクを作成しています
- count はテーブル内のデータの数を整数で返すメソッドです
フォローボタン
- != は同じではないという意味です
- if文を使用し、フォローしている時と、していない時で、機能を変更します
- method オプションでは HTTPメソッドの種類を指定します 何も指定しない場合 GET になります
- class:"" はBootstrap のオプションで、ボタンのレイアウトを変更しています
renderで表示する際はこのように書きます
users/show.html.erb
<%= render 'info', user: @user %>
User/index の view 画面
こちらも部分テンプレートに書いています
_index.html.erb
<% users.each do |user| %>
フォロー <%= user.followers.count %>
フォロワー <%= user.followeds.count %>
<% if current_user != user %>
<% if current_user.following?(user) %>
<%= link_to "フォロー外す", user_relationships_path(user.id), method: :delete %>
<% else %>
<%= link_to "フォローする", user_relationships_path(user.id), method: :post %>
<% end %>
<% end %>
今回書いてある機能は users/show ページと同じです
フォロー/フォロワーの一覧画面
controllerに定義します
users_controller
def follows
user = User.find(params[:id])
@users = user.following_users
end
def followers
user = User.find(params[:id])
@user = user.follower_users
end
メモ
- Userモデルから id をもらいます
- following_user はテーブル名です
- follower_user はテーブル名です
続いて、フォローしているユーザーの一覧とフォローされているユーザーの一覧を作成します
views/users の配下に
followers.html.erb follows.html.erb
の2つを作成します
followers.html.erb
<h2>Followers User</h2>
<% if @user.exists? %>
<table class='table' >
<thead>
<tr>
<th>image</th>
<th>name</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% @user.each do |user| %>
<tr>
<td>
<%= link_to user_path(user) do %>
<%= image_tag user.get_profile_image, size: '50x50' %>
<% end %>
</td>
<td>
<%= user.name %>
</td>
<td>
<%= link_to follows_user_path(user) do %>
フォロー<%= user.followers.count %>
<% end %>
</td>
<td>
<%= link_to followers_user_path(user) do %>
フォロワー<%= user.followeds.count %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p>ユーザーはいません</p>
<% end %>
follows.html.erb
<h2>Follows User</h2>
<% if @users.exists? %>
<table class='table'>
<thead>
<tr>
<th>image</th>
<th>name</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr>
<td>
<%= link_to user_path(user) do %>
<%= image_tag user.get_profile_image, size: '50x50' %>
<% end %>
</td>
<td>
<%= user.name %>
</td>
<td>
<%= link_to follows_user_path(user) do %>
フォロー<%= user.followers.count %>
<% end %>
</td>
<td>
<%= link_to followers_user_path(user) do %>
フォロワー<%= user.followeds.count %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<p>ユーザーはいません</p>
<% end %>
これで、フォロー/フォロワーの一覧画面が完成です。
こちらの記事を参考にさせていただきました。
Discussion