LoginSignup
3
1

More than 3 years have passed since last update.

いいね機能の実装(rails5)

Posted at

teratail風のアプリケーションで質問や回答に対してイイねができるようにする

  • 今回は質問にだけ機能を実装する

完成イメージ

イイねイメージ.gif

画面設計っぽいやつ

イイね機能.png

前提

CRUDできるアプリケーションはできていること

登場するモデル

  • user
  • question
  • like

モデルの改修

  • 以下liked_questionsでは中間テーブルであるlikeテーブルを通(through)してユーザがイイねしている質問を取得できる。
models/user.rb
class User < ApplicationRecord
#追加分のみ
  has_many :likes, dependent: :destroy
  has_many :liked_questions, through: :likes, source: :question
end
  • 以下liked_usersでは中間テーブルであるlikeテーブルを通(through)してイイねしているユーザを取得する
  • userはquestionテーブルのuser_id
models/question.rb
#追加分のみ
class Question < ApplicationRecord
  has_many :likes
  has_many :liked_users, through: :likes, source: :user
end

モデルを作る(新規)

  • モデル名:Like
  • イイねにバリデーションをつける
  • userは1つの投稿に対して1つしかいいねをつけられないようにする。
  • (今回は自分の投稿にもいいねができる)

rails g model like post:references user:references
rails db:migrate

models/like.rb
class Like < ApplicationRecord
# 追加分のみ
  validates_uniqueness_of :post_id, scope: :user_id
end

ルーティング

routes.rb
#イイねのCD部分のみ
  resources :questions do
    post :confirm,action: :confirm_new, on: :new
    resources :likes, only: [:create, :destroy]
    resources :answers

コントローラ

  • イイね機能は独自のviewを持つわけではないので任意のviewへ飛ばす。
likes_controller.rb
class LikesController < ApplicationController
    def create
        @like = current_user.likes.create(question_id: params[:question_id])
        redirect_back(fallback_location: root_path)
    end

    def destroy
        @like = Like.find_by(question_id: params[:question_id], user_id: current_user.id)
        @like.destroy
        redirect_back(fallback_location: root_path)
    end
end
  • questions_controllershowアクションに@likeをセット。
questions_controller.rb
def show
    @answer = Answer.new
    @like = Like.new
  end

既にイイねしているかの確認メソッドを定義

models/user.rb
    def already_liked?(question)
        self.likes.exists?(question_id: questions.id)
    end

Viewを編集

  • 質問に対してイイねしている・していないでボタンの表示を変える
questions/show.html
h3
  | いいね件数: #{@question.likes.count}
- if current_user.already_liked?(@question)
  = button_to 'いいねを取り消す', question_like_path(@question), class: 'btn btn-success',method: :delete
- else
  = button_to 'いいね', question_likes_path(@question),class: 'btn btn-success'
h2 いいねしたユーザー
- @question.liked_users.each do |user|
  li= user.email
  • ユーザの詳細画面にてイイねした質問を表示するためにusers/show.html.slimの中にusers/_like.html.slimを埋め込む。以下はbootstrapでのタブ表示の例。お好みで。
users/show.html

  nav
    #nav-tab.nav.nav-tabs role="tablist"
      a#nav-likes-tab.nav-item.nav-link aria-controls="nav-likes" aria-selected="false" data-toggle="tab" href="#nav-likes" role="tab" class="col-md-2"
        =  "likes:#{@user.liked_questions.count}"
    #nav-tabContent.tab-content.mt-3
      #nav-likes.tab-pane.fade aria-labelledby="nav-likes-tab" role="tabpanel"
        = render 'users/likes', { user: @user }
user/_like.html
- user.liked_questions.each do |question|
            = "質問者:#{question.user.name}"
            = link_to question.title, question_path(question)

以上。

  • 次回は非同期バージョンを執筆したいです。
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1