[Ruby on Rails] Follow function implementation: Bidirectional

Target

follow.gif

Development environment

ruby 2.5.7 Rails 5.2.4.3 OS: macOS Catalina

Premise

-Build login environment with devise

flow

1 Create model 2 Modify model <-This is the most difficult 3 Create controller 4 Fix routing 5 Create view

Creating a model

This time we created a relationship model

Terminal


$ rails g model Relationship follower_id:integer followed_id:integer

Terminal


$ rails db:migrate
Supplement The follower_id and followed_id are fictitious ids, which will be described and used later in the modification of the user model.

Modify model

app/models/relationship.rb


  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"
Supplement Change the method name and get the user record associated with @relationship in the form of @ relationship.follower. * The method name change is to separate followers and followers.

app/models/user.rb


  has_many :follower, class_name: "Relationship", foreign_key: "follower_id", dependent: :destroy #Get follow
  has_many :followed, class_name: "Relationship", foreign_key: "followed_id", dependent: :destroy #Get followers
  has_many :following_user, through: :follower, source: :followed #The person you are following
  has_many :follower_user, through: :followed, source: :follower #People who follow me

  #Follow the user and use it later in the controller.
  def follow(user_id)
    follower.create(followed_id: user_id)
  end
  
  #Unfollow the user and use it later in the controller.
  def unfollow(user_id)
    follower.find_by(followed_id: user_id).destroy
  end
  
  #Returns true if following, will be used later in view.
  def following?(user)
    following_user.include?(user)
  end
Supplement 1 [About lines 1 and 2]
has_many :follower
First, the user has many followers,
class_name: "Relationship"
Make it possible to get the @relationship record associated with @user,
foreign_key: "follower_id"
When accessing the relaitonships table, use follow_id as the entrance
dependent: :destroy
Delete when user is gone
Supplement 2 [About the 3rd and 4th lines]
has_many :following_user
First, user has many following_users,
through: :follower
Make following_user available through follower
source: :followed
Make it available with user.following_user.
Supplement 3 [About (followed_id: user_id)] (followed_id: user_id) is Substitute user_id for followed_id It is easy to understand if you imagine it like this. The rest is literally meaning.

Create controller

Terminal


$ rails g controller relationships

rb:app/controllers/relationships.controller.rb


  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

This time in app / views / homes / mypage.html.erb Described in the following location to display a list of followers and followers.

rb:app/controllers/homes.controller.rb


  def mypage
    @following_users = current_user.following_user
    @follower_users = current_user.follower_user
  end

Fix routing

rb:config.routes.rb


resources :users do
  resource :relationships, only: [:create, :destroy]
end

Add to view (if there is an instance variable)

erb:app/views/show.html.erb


<% if current_user != user %>
  <% if current_user.following?(@user) %>
    <%= link_to 'Unfollow', user_relationships_path(@user.id), method: :delete %>
  <% else %>
    <%= link_to 'To follow', user_relationships_path(@user.id), method: :POST %>
  <% end %>
<% end %>

erb:app/views/homes/mypage.html.erb


<div>
Number of followers:<%= current_user.follower.count %>
Number of followers:<%= current_user.followed.count %>
</div><br><br>
<table>
	<caption>following</caption>
	<thead>
		<tr>
			<th>username</th>
			<th></th>
		</tr>
	</thead>
	<tbody>
		<% @following_users.each do |following_user| %>
		<tr>
			<td><%= following_user.name %></td>
			<td><%= link_to 'Unfollow', user_relationships_path(following_user.id), method: :delete %></td>
		</tr>
		<% end %>
	</tbody>
</table><br><br>

<table>
	<caption>Follower</caption>
	<thead>
		<tr>
			<th>Follower name</th>
		</tr>
	</thead>
	<tbody>
		<% @follower_users.each do |follower_user| %>
		<tr>
			<td><%= follower_user.name %></td>
		</tr>
		<% end %>
	</tbody>
</table>

reference

-How to make a follow function with Rails -Definition of class_name in association! -[Rails] For you who want to give an alias to a many-to-many association

Recommended Posts