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 function ② Implementation 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
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
.
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.
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.
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
.
However, in this state, users who are not logged in If you access the URL directly, you will get an error. ↓
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.
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.
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