[RUBY] Make an instagram clone app ④

Introduction

As the title suggests, we will create a simplified Instagram app. I will write the article in the following steps, so I hope you will read it step by step.

App creation-Implementation of login functionImplementation of photo posting function ③ [Implementation of user page] (https://qiita.com/maca12vel/items/c716702b02f977303011) ④ [Implementation of follow function] (https://qiita.com/maca12vel/items/2760d33f3683fac91de5) ← Imakoko ⑤ Implementation of post deletion function

Modeling

Terminal


rails g model follow user:belongs_to target_user:belongs_to

Modify the migration file. Change foreign_key of target_user to ** false **.

db/migrate/2020**********_create_follows.rb


class CreateFollows < ActiveRecord::Migration[6.0]
  def change
    create_table :follows do |t|
      t.belongs_to :user, null: false, foreign_key: true
      t.belongs_to :target_user, null: false, foreign_key: false

      t.timestamps
    end
  end
end

Once fixed, run rails db: migrate.

Relation settings

Set the relation to the follow model. Specify class_name and foreign_key for target_user.

app/models/follow.rb


class Follow < ApplicationRecord
  belongs_to :user
  belongs_to :target_user, class_name: 'User', foreign_key: 'target_user_id'
end

We will also set relationships for the ʻuser model. active_relationships passive_relationships Will be described.

app/models/user.rb


class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :active_relationships, class_name: 'Follow', foreign_key: 'user_id'
  has_many :passive_relationships, class_name: 'Follow', foreign_key: 'target_user_id'
  has_many :followings, through: :active_relationships, source: :target_user
  has_many :followers, through: :passive_relationships, source: :user
  has_many :photos
end

This completes the relationship.

follows controller creation

Terminal


rails g controller follows

Don't forget to set up the routing as well.

routes.rb


Rails.application.routes.draw do
  root 'homes#index'

  devise_for :users

  resources :photos
  resources :users do
    resource :follow #← here
  end
end

The URL should now look like `ʻuser / user_id / follow``.

Next, edit the follows controller.

folows_controller.rb


class FollowsController < ApplicationController
  before_action :authenticate_user!

  def create
    current_user.active_relationships.create(target_user_id: params[:user_id])

    redirect_to [:user, {id: params[:user_id] }]
  end

  def destroy
    current_user.active_relationships.find_by(target_user_id: params[:user_id]).destroy

    redirect_to [:user, {id: params[:user_id] }]
  end
end

By setting before_action: authenticate_user! Only logged-in users can "follow / unfollow".

Set the follow movement with the create action. The redirect destination is [: user, {id: params [: user_id]}] It is set to transition to the user_id of user, that is, the user's detail page.

Set the unfollow movement in the destroy action. First get the record you are following with find_by instead of create. Then, it destroys the record acquired by destroy. I think the redirect destination is the same and it's okay.

Create follow / unfollow link in view file

erb:app/views/users/show.html.erb


<h3><%= @user.email %></h3>

#↓↓↓↓↓↓↓↓↓↓ From here ↓↓↓↓↓↓↓↓↓↓
<% if current_user.active_relationships.exists?(target_user_id: @user.id) %>
  <%= link_to 'unfollow', [@user, :follow], method: :delete %>
<% else %>
  <%= link_to 'follow', [@user, :follow], method: :post %>
<% end %>
#↑↑↑↑↑↑↑↑↑↑ Up to here ↑↑↑↑↑↑↑↑↑↑

<div>
  <%= link_to 'followings', [@user, :followings] %>
</div>
<div>
  <%= link_to 'followers', [@user, :followers] %>
</div>

<% @user.photos.each do |photo| %>
  <div>
    <p><%= photo.caption %></p>
    <%= image_tag photo.image %>
  </div>
<% end %>

With conditional branching If current_user was already following the user Display the link for unfollowing. → ** method: delete ** If you haven't followed yet, a link for following will be displayed. → ** method: post **

So far, let's check it with a browser once. If it looks like the following, it is successful. Jump to the user details page and press follow to complete the follow. Then follow changes to unfollow. Press unfollow to unfollow and return to follow. Image from Gyazo

However, in this state, users who are not logged in If you access the URL directly, you will get an error. ↓ Image from Gyazo

This is because the conditional branch uses current_user. Therefore, we will add more conditional branches. Insert the conditional branch with ↓. <% if user_signed_in? && current_user != @user %> <% end %>

erb:app/views/users/show.html.erb


<h3><%= @user.email %></h3>

<% if user_signed_in? && current_user != @user %> #← here
  <% if current_user.active_relationships.exists?(target_user_id: @user.id) %>
    <%= link_to 'unfollow', [@user, :follow], method: :delete %>
  <% else %>
    <%= link_to 'follow', [@user, :follow], method: :post %>
  <% end %>
<% end %> #← here

<div>
  <%= link_to 'followings', [@user, :followings] %>
</div>
<div>
  <%= link_to 'followers', [@user, :followers] %>
</div>

<% @user.photos.each do |photo| %>
  <div>
    <p><%= photo.caption %></p>
    <%= image_tag photo.image %>
  </div>
<% end %>

User is signed in And current_user is not the user on the user detail page

It means that the conditional branch is added.

Now, if you are not signed in, you will not see the "Follow / Unfollow" link. Also, it will not be displayed when you jump to your details page.

This almost completes the follow function, Finally, I would like to see a list of users who are being followed.

Creating a followings / followers controller

Terminal


rails g controller followings

Terminal


rails g controller followers

Don't forget to set the routing as well.

routes.rb


Rails.application.routes.draw do
  root 'homes#index'

  devise_for :users

  resources :photos
  resources :users do
    resource :follow
    resources :followings #← here
    resources :followers #← here
  end
end

We will also describe each in the controller.

folowings_controller.rb


class FollowingsController < ApplicationController
  def index
    @followings = User.find(params[:user_id]).followings
  end
end

folowers_controller.rb


class FollowersController < ApplicationController
  def index
    @followers = User.find(params[:user_id]).followers
  end
end

And we will create a view. Display following / follower ```emailwith link_to`` respectively, I am creating a link to the user details page.

erb:app/views/followings/index.html.erb


<% @followings.each do |following| %>
  <div>
    <%= link_to following.email, [following] %>
  </div>
<% end%>

erb:app/views/followers/index.html.erb


<% @followers.each do |follower| %>
  <div>
    <%= link_to follower.email, [follower] %>
  </div>
<% end%>

The specification of path is [following]user_followings_path [follower]user_followers_path But it's okay, so it's easy to understand.

Finally, create a link on the user detail page.

erb:app/views/users/show.html.erb


<h3><%= @user.email %></h3>

<% if user_signed_in? && current_user != @user %>
  <% if current_user.active_relationships.exists?(target_user_id: @user.id) %>
    <%= link_to 'unfollow', [@user, :follow], method: :delete %>
  <% else %>
    <%= link_to 'follow', [@user, :follow], method: :post %>
  <% end %>
<% end %>

#↓↓↓↓↓↓↓↓↓↓ From here ↓↓↓↓↓↓↓↓↓↓
<div>
  <%= link_to 'followings', [@user, :followings] %>
</div>
<div>
  <%= link_to 'followers', [@user, :followers] %>
</div>
#↑↑↑↑↑↑↑↑↑↑ Up to here ↑↑↑↑↑↑↑↑↑↑

<% @user.photos.each do |photo| %>
  <div>
    <p><%= photo.caption %></p>
    <%= image_tag photo.image %>
  </div>
<% end %>

The path of the page to be displayed is Followings of @ user Followers of @ user It will be.

Let's check the operation with this. If it looks like the following, it is successful. Image from Gyazo

It's fast and difficult to understand, but it starts from the state where you are logged in with sample. ① sample jumps to the detail page of `ʻexampleand ** follow **. ② If you jump to the following link on the sample details page, you can see the exampleyou just followed. ③ If you jump to the followerslink on the detail page of example, you can see sample``.


that's all. Thank you for your hard work.

Recommended Posts

Make an instagram clone app ④
Make an instagram clone app ②
Make an instagram clone app ③
Make an instagram clone app ①
Make an android app. (Day 5)
Make an android app. (First day)
I want to make an ios.android app
App development beginners tried to make an Android calculator app
Let's make the app better
How to make an app using Tensorflow with Android Studio
Is it an Android app?
Make an FPS counter in Swift
Create an app with Spring Boot 2
Create an app with Spring Boot
How to make an app with a plugin mechanism [C # and Java]