🐣

[Ruby on Rails] フォローフォロワー機能の作成

2023/07/07に公開

テーブルの設計

カラム名 データ型 カラムの説明
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