LoginSignup
5
15

More than 3 years have passed since last update.

【Rails】Ajaxを用いた非同期フォロー機能の実装

Last updated at Posted at 2020-04-09

目標

ezgif.com-video-to-gif.gif

開発環境

・Ruby: 2.5.7
・Rails: 5.2.4
・Vagrant: 2.2.7
・VirtualBox: 6.1
・OS: macOS Catalina

前提

下記実装済み。

Slim導入
Bootstrap3導入
ログイン機能実装

フォロー機能を実装

1.モデル

ターミナル
$ rails g model Relationship follower_id:integer followed_id:integer
ターミナル
$ rails db:migrate
schema.rb
ActiveRecord::Schema.define(version: 2020_04_05_115005) do
  create_table "relationships", force: :cascade do |t|
    t.integer "follower_id"
    t.integer "followed_id"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end  
end
user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable,:validatable

  has_many :books, dependent: :destroy
  has_many :follower, class_name: 'Relationship', foreign_key: 'follower_id', dependent: :destroy
  has_many :followed, class_name: 'Relationship', foreign_key: 'followed_id', dependent: :destroy
  has_many :following_user, through: :follower, source: :followed
  has_many :follower_user, through: :followed, source: :follower

  # ユーザーをフォローする
  def follow(user_id)
    follower.create(followed_id: user_id)
  end

  # ユーザーをアンフォローする
  def unfollow(user_id)
    follower.find_by(followed_id: user_id).destroy
  end

  # フォローしているかを確認する
  def following?(user)
    following_user.include?(user)
  end
end

has_many :follower, class_name: 'Relationship', foreign_key: 'follower_id', dependent: :destroy
➡︎ Relationshipモデルのfollower_idにuser_idを格納

has_many :followed, class_name: 'Relationship', foreign_key: 'followed_id', dependent: :destroy
➡︎ Relationshipモデルのfollower_idにuser_idを格納

has_many :following_user, through: :follower, source: :followed
➡︎ 自分がフォローしているユーザー

has_many :follower_user, through: :followed, source: :follower
➡︎ 自分をフォローしているユーザー

relationship.rb
class Relationship < ApplicationRecord
  belongs_to :follower, class_name: 'User'
  belongs_to :followed, class_name: 'User'
end

2.コントローラー

ターミナル
$ rails g controller relationships
relationships_controller.rb
class RelationshipsController < ApplicationController
  # フォローする
  def follow
    current_user.follow(params[:id])
    redirect_to users_path
  end

  # アンフォローする
  def unfollow
    current_user.unfollow(params[:id])
    redirect_to users_path
  end
end
users_controller.rb
class UsersController < ApplicationController
  def index
    @users = User.all
  end

  # 自分がフォローしているユーザー一覧
  def following
    @user = User.find(params[:user_id])
    @followings = @user.following_user.where.not(id: current_user.id)
  end

  # 自分をフォローしているユーザー一覧
  def follower
    @user = User.find(params[:user_id])
    @followers = @user.follower_user.where.not(id: current_user.id)
  end
end

3.ルーティング

routes.rb
Rails.application.routes.draw do
  post 'follow/:id', to: 'relationships#follow', as: 'follow'
  post 'unfollow/:id', to: 'relationships#unfollow', as: 'unfollow'
  get 'users/following/:user_id', to: 'users#following', as:'users_following'
  get 'users/follower/:user_id', to: 'users#follower', as:'users_follower'
end

4.ビュー

users/index.html.slim
.row
  .col-xs-2

  .col-xs-8
    table.table
      thead
        tr
          th
            | 氏名
          th
            | 自己紹介
          th
          th
          th

      tbody
        - @users.each do |user|
          tr
            td
              = link_to user do
                = user.name
            td
              = user.introduction
            td
              / 自分がフォローしているユーザー一覧
              = link_to "#{ user.follower.count }フォロー中", users_following_path(user)
            td
              / 自分をフォローしているユーザー一覧
              = link_to "#{ user.followed.count }フォロワー", users_follower_path(user)
            td
              - unless user == current_user
                - if current_user.following?(user)
                  = link_to 'フォロー解除', unfollow_path(user), method: :post, class: 'btn btn-info'

                - else
                  = link_to 'フォローする', follow_path(user), method: :post, class: 'btn btn-default'


  .col-xs-2

非同期機能を実装

1.jQueryを導入

Gemfile
    gem 'jquery-rails'
ターミナル
    $ bundle
application.js
    //= require rails-ujs
    //= require activestorage
    //= require turbolinks
    //= require jquery
    //= require_tree .

2.ビューを編集

users/index.html.slim
/ 各フォロー中一覧のリンクにIDを付与
td id='following-count_#{ user.id }'
  = link_to "#{ user.follower.count }フォロー中", users_following_path(user)
/ 各フォロワー一覧のリンクにIDを付与
td id='follower-count_#{ user.id }'
  = link_to "#{ user.followed.count }フォロワー", users_follower_path(user)
td
  - unless user == current_user
    / 各フォローボタンにIDを付与
    span id='follow-button_#{ user.id }'
      / フォローボタンをパーシャル化
      = render 'users/follow-button', user: user
users/_follow-button.html.slim
/ フォローボタンに「remote: true」を付与
- if current_user.following?(user)
  = link_to 'フォロー解除', unfollow_path(user), method: :post, class: 'btn btn-info', remote: true

- else
  = link_to 'フォローする', follow_path(user), method: :post, class: 'btn btn-default', remote: true

「remote: true」を付与する事で、JavaScriptファイルを呼び出せる様になる。

2.JavaScriptファイルを作成

users/follow.js.erb
$("#follow-button_<%= @user.id %>").html("<%= j(render 'users/follow-button', user: @user) %>");
$("#follower-count_<%= @user.id %>").html('<%= link_to "#{ @user.followed.count }フォロワー", users_follower_path(@user) %>');
$("#following-count_<%= current_user.id %>").html('<%= link_to "#{ current_user.follower.count }フォロー中", users_following_path(@user) %>');
users/unfollow.js.erb
$("#follow-button_<%= @user.id %>").html("<%= j(render 'users/follow-button', user: @user) %>");
$("#follower-count_<%= @user.id %>").html('<%= link_to "#{ @user.followed.count }フォロワー", users_follower_path(@user) %>');
$("#following-count_<%= current_user.id %>").html('<%= link_to "#{ current_user.follower.count }フォロー中", users_following_path(@user) %>');

$("#follow-button_<%= @user.id %>").html("<%= j(render 'users/follow-button', user: @user) %>");
➡︎ フォローボタンを非同期で処理

$("#follower-count_<%= @user.id %>").html('<%= link_to "#{ @user.followed.count }フォロワー", users_follower_path(@user) %>');
➡︎ フォロワーカウント数を非同期で処理

$("#following-count_<%= current_user.id %>").html('<%= link_to "#{ current_user.follower.count }フォロー中", users_following_path(@user) %>');
➡︎ フォロワー中カウント数を非同期で処理

5
15
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
5
15