유저 팔로우 기능 만들기

팔로우 구현하기 - 모델 관계 설정

이번 강의에서는 팔로우를 직접 구현하기에 앞서 모델 관계를 설정하는 법을 배워보겠습니다.

  1. 용어 정의

우리가 구현할 팔로우 기능은 트위터와 유사합니다.
트위터 유저가 아니라면 팔로워, 팔로잉에 대한 개념이 헷갈릴 수 있으니
먼저 용어 정의를 하겠습니다.

팔로우(Follow)는 블로그나 뉴스등을 구독하듯이 누군가가 올린 글을 계속해서 확인하고자 할 때 사용합니다.
팔로잉(Following)은 내가 누군가를 팔로우한 것입니다. 나의 팔로잉이 10명이라면,
내가 팔로우한 유저가 10명 있다는 뜻입니다.
팔로워(Follower)는 나를 팔로우하는 유저입니다. 나의 팔로워가 10명이라면,
나를 팔로우하는 유저가 10명 있다는 뜻입니다.

  1. Follow 조인 모델

팔로우를 구현하기 위한 모델 관계 설정은 꽤 복잡합니다. 보통 N:N 관계는 이전에 배웠던대로 두 모델 사이의 관계를 나타냅니다.
하지만 이번에는 팔로우를 하는 대상과 팔로우를 당하는 대상이 모두 User이므로
두 모델이 아니라 User 모델만을 가지고 N:N 관계를 구현해야 합니다.

User 모델만으로는 구현할 수 없고, 중간에서 팔로워유저와 팔로잉유저를 이어주는 조인 모델이 필요합니다.
그리고 N:N 관계를 구현하기 위해 조인 모델을 거치는 has_many :through를 사용할 것입니다.

Follow라는 조인 모델을 생성합니다.

rails g model Follow

# db/migrate/xxxxxxxxxx_create_follows.rb

class CreateFollows < ActiveRecord::Migration[5.0]
  def change
    create_table :follows do |t|

      # follower: 팔로우를 신청한 사람
      # followed: 팔로우 신청을 받은 사람
      t.integer :follower_id
      t.integer :followed_id

      t.timestamps
    end
    add_index :follows, :follower_id
    add_index :follows, :followed_id
    add_index :follows, [:follower_id, :followed_id], unique: true
  end
end

Follow 모델은 조인모델이기 때문에 연결해줄 2개의 id를 가지고 있습니다. follower_id와 followed_id는 User 모델의 id가 들어갈 컬럼이며
follower_id에는 팔로우를 신청한 유저의 id가, followed_id에는 팔로우 신청을 받은 유저의 id가 들어가게 됩니다.

작성이 완료되면 rake db:migrate 명령어를 실행시켜줍니다.

  1. User - Follow 관계 설정

3-1. Follow 모델

Follow 모델은 외래키(foreign_key)를 가지고 있는 입장이기 때문에 모델 관계 설정에 belongs_to를 사용합니다.
관계 이름(follower, followed)과 대상 모델 이름(User)이 다르기 때문에 class_name 옵션을 사용해서 모델명을 별도로 명시해줍니다.

class Follow < ApplicationRecord
  # 팔로우 신청한 유저
  # 관계 이름 : follower
  # 모델 명 : User
  belongs_to :follower, class_name: "User"

  # 팔로우 신청 받은 유저
  # 관계 이름 : followed
  # 모델 명 : User
  belongs_to :followed, class_name: "User"
end

여기까지 완료하면 Follow 모델 객체에서 팔로우를 신청한 유저와 신청을 받은 유저를 불러올 수 있습니다.

# 팔로우를 신청한 유저는 5번, 팔로우 신청을 받은 유저는 4번 id를 가지고 있음
2.2.3 :022 >   follow = Follow.find_by(id: 1)
 => #<Follow id: 1, follower_id: 5, followed_id: 4, created_at: "2016-06-12 12:55:30", updated_at: "2016-06-12 12:55:30">
2.2.3 :024 >   follow.follower
 => #<User id: 5, ..., created_at: "2016-06-12 10:55:29", updated_at: "2016-06-12 10:55:29">
2.2.3 :026 >   follow.followed
 => #<User id: 4, ..., created_at: "2016-06-12 10:52:46", updated_at: "2016-06-12 10:52:46">

팔로우를 신청한 유저의 id는 Follow 모델의 follower_id에, 팔로우 당하는 입장의 유저의 id는 followed_id에 존재해야 합니다.

3-2. 팔로워

User와 Follow 모델은 1:N 관계를 적용시킬 수 있습니다.
단, 외래키(foreign_key)가 모델 이름과 같은 user_id가 아닌 followed_id이기 때문에 외래키 이름을 별도로 명시해줘야합니다.
그리고 관계 이름(follower_relations)와 모델명(Follow)가 같지 않으므로 class_name으로 모델명도 명시해줍니다.

class User < ApplicationRecord
  ...

  # 관계 이름 : follower_relations(다른 이름으로 변경 가능)
  # 외래키 : followed_id
  # 모델명 : Follow
  has_many :follower_relations, foreign_key: "followed_id", class_name: "Follow"
end

이 상태에서 user.follower_relations 코드를 실행하면 Follow 목록이 반환됩니다. 우리가 원하는 것은 유저의 목록이므로
조금 더 작성해봅시다.

class User < ApplicationRecord
  ...

  has_many :follower_relations, foreign_key: "followed_id", class_name: "Follow"

  # 관계 이름 : followers (다른 이름으로 변경 가능)
  # follow_relations를 통해 가져올 값 : follower ( follow.follower )
  has_many :followers, through: :follower_relations, source: :follower
end

이제 user.followers로 모든 팔로워 유저 목록을 가져올 수 있습니다!

3-3. 팔로잉

팔로잉관계도 팔로워와 완전히 같습니다. 관계 이름과 외래키 정도만 바꿔주면 됩니다.

class User < ApplicationRecord
  ...

  has_many :follower_relations, foreign_key: "followed_id", class_name: "Follow"
  has_many :followers, through: :follower_relations, source: :follower

  has_many :following_relations, foreign_key: "follower_id", class_name: "Follow"
  has_many :followings, through: :following_relations, source: :followed
end

user.followings로 내가 팔로잉하는 유저 목록을 가져올 수 있습니다.

팔로우 기능 구현

팔로우 모델링을 마쳤으니 컨트롤러와 뷰를 작성해보도록 하겠습니다.

팔로우와 팔로우 취소 기능을 구현하고 팔로워와 팔로잉 수를 표시해보겠습니다.

app/views/posts/_post.html.erb 팔로우/팔로우 취소 버튼 구현

<% if user_signed_in? && current_user != post.user %>
  <% if current_user.followings.include?(post.user) %>
    <button class="right btn">팔로우 취소</button>
  <% else %>
    <button class="right btn">팔로우</button>
  <% end %>
<% end %>

rails g controller follows --no-assets 팔로우 컨트롤러 생성합니다. --no-assets 옵션을 추가하면 css와 js 자동생성을 하지 않습니다.

팔로우 버튼을 form 형태로 수정합니다.

app/views/posts/_post.html.erb

...
<% if user_signed_in? && current_user != post.user %>
  <% if current_user.followings.include?(post.user) %>
    <%= form_tag follow_path(post.user.id), method: :delete, class: "right" do %>
      <button class="btn">팔로우 취소</button>
    <% end %>
  <% else %>
    <%= form_tag follows_path, class: "right" do %>
      <input type="hidden" name="followed_id" value="<%= post.user.id %>" />
      <button class="btn">팔로우</button>
    <% end %>
  <% end %>
<% end %>
...

라우트 규칙을 설정합니다.

config/routes.rb

resources :follows, only: [:create, :destroy]

각 버튼과 연결될 액션을 작성합니다.

app/controllers/follows_controller.rb

class FollowsController < ApplicationController
  before_action :authenticate_user!

  def create
    Follow.create(followed_id: params[:followed_id],
                  follower_id: current_user.id)
    redirect_to :back
  end

  def destroy
    Follow.find_by(followed_id: params[:id],
                   follower_id: current_user.id).destroy
    redirect_to :back
  end
end

사용자 프로필 정보에 팔로우 정보를 표시해줍니다.

app/views/posts/index.html.erb

<p>팔로워 : <%= current_user.followers.length %></p>
<p>팔로잉 : <%= current_user.followings.length %></p>

results matching ""

    No results matching ""