Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
0
Help us understand the problem. What is going on with this article?
@teipoi

[Rails] いいねをつける

1人のユーザーは1つのプロフィールにいいねでき、
MVCの命名は「like」とします。

Image from Gyazo

% rails g model like user_id:integer profile_id:integer
モデルとマイグレーションファイルを作成します。

テーブル

db/migrate/〜_create_likes.rb
class CreateLikes < ActiveRecord::Migration[6.0]
  def change
    create_table :likes do |t|
      t.integer :user_id
      t.integer :profile_id

      t.timestamps
    end
  end
end

% rails db:migrate
likesテーブルを作成します。

モデル

models/like.rb
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :profile
end
models/profile.rb
has_many :likes, dependent: :destroy
models/user.rb
has_many :likes, dependent: :destroy

アソシエーションを定義します。


models/like.rb
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :profile

  validates_uniqueness_of :profile_id, scope: :user_id
end

バリデーションを設定します。
profile_idとuser_idの組み合わせが一意性という制限です。

scopeとは、modelで使えるActive Recordの機能の一部です。
Railsガイド


models/like.rb
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :profile

  validates_uniqueness_of :profile_id, scope: :user_id

  def already_liked?(profile)
    self.likes.exists?(profile_id: profile.id)
  end
end

ユーザーが既にいいねしているかを確認するメソッドを作成します。
理由は、このあとviewsで条件分岐に使うからです。

exists?
該当の値があればtrue、なければfalseを返すメソッドです。

selfにはcurrent_userのデータが入ります。
データが入ってない現在のselfの中はこんな感じ↓
Image from Gyazo

要約:
current_userに紐付いたlikesテーブルの中で、profile_id:に現在いいねしようとしている
プロフィールのidが存在しているか?

ルーティング

config/routes.rb
resources :profiles do
    resource :likes, only: [:create, :destroy]
end

ルーティングを設定します。

コントローラー

likes_controller.rb
class LikesController < ApplicationController
  def create
    @like = current_user.likes.create(profile_id: params[:profile_id])
    redirect_back(fallback_location: root_path)
  end

  def destroy
    @profile = Profile.find(params[:profile_id])
    @like = current_user.likes.find_by(profile_id: @profile.id)
    @like.destroy
    redirect_back(fallback_location: root_path)
  end
end

redirect_back
直前のページにリダイレクトするメソッドです。
index, showなど、複数の画面でいいねしたいのでこう書いています。
もしshowでしかいいねしないといった場合はredirect_toで大丈夫です。

fallback_location: url
もし直前のページが見つからなかった場合に、指定のURLに遷移させます。
エラーが発生したケースを想定しての記述です。

ビュー

views/show.html.erb
 <% if user_signed_in? && current_user != @profile.user %>
      <% if current_user.already_liked?(@profile) %>
        <%= link_to profile_likes_path(@profile), method: :delete do %>
          <svg xmlns="http://www.w3.org/2000/svg" class= "unlike" width="16" height="16" fill="currentColor" class="bi bi-heart-fill" viewBox="0 0 16 16">
            <path fill-rule="evenodd" d="M8 1.314C12.438-3.248 23.534 4.735 8 15-7.534 4.736 3.562-3.248 8 1.314z"/>
          </svg>
        <% end %>
      <% else %>
        <%= link_to profile_likes_path(@profile), method: :post do %>
          <svg xmlns="http://www.w3.org/2000/svg" class= "like" width="16" height="16" fill="currentColor" class="bi bi-heart" viewBox="0 0 16 16">
            <path d="M8 2.748l-.717-.737C5.6.281 2.514.878 1.4 3.053c-.523 1.023-.641 2.5.314 4.385.92 1.815 2.834 3.989 6.286 6.357 3.452-2.368 5.365-4.542 6.286-6.357.955-1.886.838-3.362.314-4.385C13.486.878 10.4.28 8.717 2.01L8 2.748zM8 15C-7.333 4.868 3.279-3.04 7.824 1.143c.06.055.119.112.176.171a3.12 3.12 0 0 1 .176-.17C12.72-3.042 23.333 4.867 8 15z"/>
          </svg>
        <% end %>
      <% end %>
      <%= @profile.likes.count %>
  <% end %>

ビューを作成します。
少し前に作成したalready_liked?メソッドを使って、
既にいいねしてあれば削除、まだいいねしてなければ保存するという条件分岐をします。

svgはアイコンの表示です。
<%= @profile.likes.count %>はいいねの数を表示しています。


views/show.html.erb
<%= link_to profile_likes_path(@profile), method: :post do %>

<%= link_to profile_likes_path(@profile), method: :post, remote: true do %>

非同期にする場合は、link_toにremote: trueを付与します。

0
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
teipoi
自分用 日々の学びをアウトプットしています😌

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
0
Help us understand the problem. What is going on with this article?