LoginSignup
2
2

More than 3 years have passed since last update.

【Rails6】非同期(Ajax)でフォロー機能を実装する

Posted at

前提

  • deviseでユーザーに関する機能作成済み
  • jqueryが使える環境を構築済み

概要

フォロー機能の仕組みについては、RailsTutorialに詳しく書かれているので、参照することをお勧めします。今回用いるカラム名やモデル名は以下の通りです。メモ程度ですが参考程度に載せておきます。

Untitled (13)-7.jpg

Relationshipモデルを作成

コンソールでrelationshipモデルを作成

rails g model relationships
  • 参照
    • フォロワー: userテーブルを参照する
    • フォロー : followという名前でuserテーブルを参照する
  • index
    • user_idとfollow_idが一致することが無い様に、複合キーインデックスを追加
    • これにより、「自分が自分をフォローする」ということを防げる
20210104064312_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[6.0]
  def change
    create_table :relationships do |t|
      t.references :user, foreign_key: true
      t.references :follow, foreign_key: { to_table: :users }

      t.timestamps

      t.index [:user_id, :follow_id], unique: true
    end
  end
end

マイグレーションを実行

rails db:migrate

relationshipモデルとuserモデルのリレーションは以下の通り記述する。
また、validationも記述。

relationship.rb

class Relationship < ApplicationRecord
  belongs_to :user
  belongs_to :follow, class_name: 'User'

  validates :user_id, presence: true
  validates :follow_id, presence: true
end
  • 関連付けについては、上記画像を参照していただけると幸いです。
  • 「フォローする」「フォローを外す」「フォローしているか確認」のメソッドは何度も使用するので、定義しておきます。
relationship.rb
class User < ApplicationRecord
  has_many :relationships, dependent: :destroy
  has_many :followings, through: :relationships, source: :follow
  has_many :reverse_of_relationships, class_name: 'Relationship', foreign_key: 'follow_id', dependent: :destroy
  has_many :followers, through: :reverse_of_relationships, source: :user

  def follow(other_user_id)
    relationships.find_or_create_by(follow_id: other_user_id) unless id == other_user_id.to_i
  end

  def unfollow(other_user_id)
    relationship = relationships.find_by(follow_id: other_user_id)
    relationship.destroy if relationship
  end

  def following?(other_user)
    followings.include?(other_user)
  end
end

view controllerの作成

  • 自ユーザページの場合は、「編集ボタン」、他ユーザページの場合は、「フォローボタン」を表示する様にします。
app/views/users/show.html.erb

<div>
  <% if @user.id == current_user.id %>
    <%= link_to 'Edit', edit_user_registration_path(current_user) %>
  <% else %>
    <%= render partial: 'follow' %>
    <%= render partial: 'follow_count'%>
  <% end %>
</div>
app/views/users/_follow.html.erb

<span id="follow">
  <%= follow_button(@user) %>
</span>
  • follow_buttonを定義しています。
  • Bootstrapを使用している方は、フォロー中かどうかに応じてkeyにprimaryかsecondaryが入るため、ボタンの色を変えることができます。(Bootstrap不使用の方は消してしまって問題ないです。)
  • remote: true を入れることによって、Ajax通信をすることができます。
app/helpers/application_helper.html.erb
module ApplicationHelper
  def follow_button(user)
    label, key = current_user.following?(user) ? %w[フォロー中 secondary] : %w[フォローする primary]
    link_to(label, user_follow_path(@user), method: :post, remote: true, class: "btn btn-#{key} rounded-pill")
  end
end
  • javascriptで書かれています。
  • html内のidがfollowの中身をrenderすることができます。
app/views/users/follow.js.erb
$('#follow').html('<%= j(render partial: "follow") %>');
  • 忘れずにrouteも変えましょう。
  • post通信を行うために指定が必要です。
routes.rb
Rails.application.routes.draw do
  resources :users, only: %w[index show] do
    post :follow
  end
end

最後に

@user.followers.count@user.followings.countで、フォロワー数やフォロー数をカウントして表示することが可能です。こちらの記事を理解することができていれば、簡単にAjaxで実装できるので、やってみてください。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2