I will put it together for myself.
Modeling
$ rails g model Relationship follower_id:integer followed_id:integer
$ rails db:migrate
Migration file
20200723070930_create_relationships.rb
class CreateRelationships < ActiveRecord::Migration[5.2]
def change
create_table :relationships do |t|
t.integer :follower_id, null: false
t.integer :followed_id, null: false
t.timestamps
end
end
end
relationship.rb
class Relationship < ApplicationRecord
#Users to follow
belongs_to :follower, class_name: 'User'
#Users to be followed
belongs_to :followed, class_name: 'User'
validates :follower_id, presence: true
validates :following_id, presence: true
end
** class_name:'User' **: means "both follower and followed are in User"
app/models/user.rb
class User < ApplicationRecord
#Get follow
has_many :follower, class_name: 'Relationship', foreign_key: 'follower_id', dependent: :destroy
#Get followers
has_many :followed, class_name: 'Relationship', foreign_key: 'followed_id', dependent: :destroy
#The person you are following
has_many :following_user, through: :follower, source: :followed
#People who follow me (followers)
has_many :follower_user, through: :followed, source: :follower
#Follow users
def follow(user_id)
follower.create(followed_id: user_id)
end
#Unfollow users
def unfollow(user_id)
follower.find_by(followed_id: user_id).destroy
end
#Follow confirmation
def following?(user)
following_user.include?(user)
end
end
Controller creation
$ rails g controller relationships
config/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
users_controller.rb
class UsersController < ApplicationController
# @List of users that user is following
def following
@user = User.find(params[:user_id])
@followings = @user.following_user
end
# @List of users following user
def follower
@user = User.find(params[:user_id])
@followers = @user.follower_user
end
end
relationship_controller.rb
class RelationshipsController < ApplicationController
#To follow
def follow
@user = User.find(params[:id])
current_user.follow(params[:id])
render :create
end
#Unfollow
def unfollow
@user = User.find(params[:id])
current_user.unfollow(params[:id])
render :destroy
end
end
By calling create.js.erb and destroy.js.erb with render, You will be able to follow / unfollow without page transitions.
ruby:users/show.html.slim
# create.js.erb and destroy.js.Description is required to rewrite with erb
div id="follow_form"
#Partially skip the follow button part
= render 'relationships/follow', user: @user
Manually create the _follow.html.slim file under the relationships directory Paste the description of the follow button part that was skipped in the partial.
ruby:relationships/_follow.html.slim
- unless user == current_user
- if current_user.following?(user)
#remote to call js file:Add true
= link_to unfollow_path(user), method: :post, remote: true, class: 'btn btn-outline-info m-0 btn-sm' do
i.fas.fa-user following
- else
#remote to call js file:Add true
= link_to follow_path(user), method: :post, remote: true, class: 'btn btn-outline-success m-0 btn-sm' do
i.far.fa-user follow
Manually create the create.js.erb file under the relationships directory
ruby:relationships/create.js.erb
# id="follow_form"Part_follow.html.Rewrite slim content without page transition
$('#follow_form').html("<%= j(render 'relationships/follow',{ user: @user }) %>");
Manually create the destroy.js.erb file under the relationships directory
ruby:relationships/destroy.js.erb
# id="follow_form"Part_follow.html.Rewrite slim content without page transition
$('#follow_form').html("<%= j(render 'relationships/follow',{ user: @user }) %>");
Complete!
Recommended Posts