rails로 동영상 사이트에 좋아 기능 구현

15979 단어 RailsRails5

동영상 사이트에 좋은 기능을 구현해 보았습니다.



지금은 당연하게 되고 있는 좋은 기능이지만, 어떻게 만들어지고 있는지 궁금해 포트폴리오에 시험에 실장해 보았습니다. 1 유저가 복수의 동영상에 대해서 좋아하고, 또 1 동영상에 대해 복수의 유저가 좋아하는, 이른바 다대다의 관계이므로, 유저와 동영상의 중간 테이블로서 좋아요 테이블을 작성해 갑니다.

완성도





환경



rails : v5.2.4.1

~ 구현된 기능 ~
・동영상(일람 표시, 신규 투고, 상세, 편집, 삭제)
· 사용자(신규 등록, 로그인, 편집, 로그아웃, 상세)
· 페이지 네이션

구현 절차



※좋아 기능에 관한 부분만 코멘트 아웃으로 설명 쓰고 있습니다.
  • 터미널에서 라이크 모델링
  • $ rails g model Like user:references video:references
    $ rails db:migrate
    

    models/user.rb
    class User < ApplicationRecord
      devise :database_authenticatable, :registerable,
             :recoverable, :rememberable, :validatable
    
      validates :name, presence: true, uniqueness: true
      has_many :videos, dependent: :destroy
      # いいねはユーザーのdestroyに依存
      has_many :likes, dependent: :destroy
      # ユーザーがいいねしている動画
      has_many :liked_videos, through: :likes, source: :video
      # いいねしているかどうかを判定
      def already_liked?(video)
        self.likes.exists?(video_id: video.id)
      end
    end
    

    models/video.rb
    class Video < ApplicationRecord
      validates :name, :work, presence: true
      belongs_to :user
      # いいねは動画のdestroyに依存
      has_many :likes, dependent: :destroy
      # 動画にいいねしているユーザー
      has_many :liked_users, through: :likes, source: :user
    
      mount_uploader :work, VideoUploader
    end
    

    models/like.rb
    class Like < ApplicationRecord
      belongs_to :user
      belongs_to :video
      # 1人が1つの動画に1いいね
      validates_uniqueness_of :video_id, scope: :user_id
    end
    
  • 터미널에서 likes 컨트롤러 작성
  • $ rails g controller likes
    
  • "좋아요", "좋아요 취소"뿐이므로 create, destroy 만 추가

  • config/routes.rb
    Rails.application.routes.draw do
      devise_for :users
      root "videos#index"
      resources :users, only: [:edit, :update, :show]
      # いいねを動画にネストさせる
      resources :videos do
        resources :likes, only: [:create, :destroy]
      end
    end
    

    controllers/likes_controller.rb
    class LikesController < ApplicationController
    
      def create
        # 今ログインしているユーザーによるいいね
        @like = current_user.likes.create(video_id: params[:video_id])
        # 今いる画面にリダイレクト
        redirect_back(fallback_location: root_path)
      end
    
      def destroy
        # 今ログインしているユーザーがいいねしている動画を探す
        @like = Like.find_by(video_id: params[:video_id], user_id: current_user.id)
        # いいねを取り消す
        @like.destroy
        # 今いる画面にリダイレクト
        redirect_back(fallback_location: root_path)
      end
    
    end
    

    controllers/videos_controller.rb
    class VideosController < ApplicationController
    
      def index
        @videos = Video.includes(:user).page(params[:page]).order("created_at DESC").per(12)
      end
    
      def new
        @video = Video.new
      end
    
      def create
        Video.create(video_params)
        redirect_to root_path
      end
    
      def show
        @video = Video.find(params[:id])
        # いいねする
        @like = Like.new
      end
    
      def edit
        @video = Video.find(params[:id])
      end
    
      def update
        video = Video.find(params[:id])
        video.update(video_params)
      end
    
      def destroy
        video = Video.find(params[:id])
        video.destroy
        redirect_to root_path
      end
    
      private
    
      def video_params
        params.require(:video).permit(:name, :work).merge(user_id: current_user.id)
      end
    
    end
    
    end
    

    로그인하지 않은 사용자도 좋아요 수를 볼 수 있도록하려면 분기 필요

    show.html.haml
    -# ログインしている場合
    - if user_signed_in?
      -# かつ既にいいねしている場合
      - if current_user.already_liked?(@video)
        = link_to video_like_path(@video), method: :delete do
          = icon('fa', 'heart', class: 'content__show__box__top__icons__heart__already')
      -# かつまだいいねしていない場合
      - else
        = link_to video_likes_path(@video), method: :post do
          = icon('far', 'heart', class: 'content__show__box__top__icons__heart__yet')
    -# ログインしていない場合
    - else
      = icon('far', 'heart', class: 'content__show__box__top__icons__heart__yet')
        = @video.likes.count
    

    video의 index 컨트롤러에서는 video의 id 컬럼을 취득할 수 없고, 에러로 nil이 돌려주어져 버린다.
    그 때문에 일람 화면에서는 표시만으로 해, 좋아 버튼은 동작하지 않게 설정.

    index.html.haml
    -# ログインしている場合、かつ既にいいねしている場合
    - if user_signed_in? && current_user.already_liked?(video)
      = icon('fa', 'heart', class: 'content__box__top__icons__heart__already')
    -# それ意外の場合
    - else
      = icon('far', 'heart', class: 'content__box__top__icons__heart__yet')
        = video.likes.count
    

    도전


  • 동영상 목록 표시(index), 사용자별 상세 페이지(users/show)에서도 좋을 수 있도록 한다
  • 하나의 화면 업데이트없이 비동기 적으로 반영되도록 Jquery 또는 Vue로 다시 작성

  • 참고


  • Rails에서 좋아하는 기능을 구현합시다.
  • Rails 좋아하는 기능의 미니 앱을 만들자.
  • 좋아하는 기능의 DB 설계
  • 좋은 웹페이지 즐겨찾기