見本

PostAppSorcery

Gyazo

課題内容:「Like機能」の実装

内容詳細

  1. 他人の投稿を「Like」することができる
  2. その「Like」した投稿を「Unlike」することができる
  3. 自分の投稿に対しては「Like」することができない

実  装

  1. 基本的には、課題15のブックマーク機能を利用すればできると思うのでlikeモデルとlikeテーブルを作成して、user_idとpost_idの組合せのunique制約を設定する
$bin/rails g model like
class CreateLikes < ActiveRecord::Migration[5.2]
  def change
    create_table :likes do |t|
      t.references :user, null: false
      t.references :post, null: false

      t.timestamps
    end
    add_index :likes, [:user_id, :post_id], unique: :true
  end
end

データベースにindexを張る方法 - Qiita

https://310nae.com/rails-uniqueness/

  1. modelを編集する まず、like.rbを以下のように編集する
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :post
  validates_uniqueness_of :post_id, scope: :user_id
end

続いて、post.rbを「1対多」、user.rbを「多対多」にアソシエーションさせる

class Post < ApplicationRecord
  belongs_to :user
  has_many :likes, dependent: :destroy

  validates :title, presence: true, length: { maximum: 255 }
  validates :content, presence: true, length: { maximum: 65_535 }

  def liked_by?(user)
    likes.where(user_id: user).exists?
  end
end
class User < ApplicationRecord
  authenticates_with_sorcery!

  has_many :posts, dependent: :destroy
  has_many :likes, dependent: :destroy
  has_many :likes_posts, through: :likes, source: :post

  validates :password, length: { minimum: 3 }, if: -> { new_record? || changes[:crypted_password] }
  validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] }
  validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] }

  validates :email, uniqueness: true
  validates :email, presence: true
  validates :first_name, presence: true, length: { maximum: 255 }
  validates :last_name, presence: true, length: { maximum: 255 }

  def mine?(object)
    # 呼び出し元のオブジェクトのIDを示す self.id を省略した記法。
    # @user.mine?(object)のように利用すると、object.user_id と @user.id を比較する。
    object.user_id == id
  end

  def like(post)
    likes_posts << post
  end

  def unlike(post)
    likes_posts.delete(post)
  end

  def like?(post)
    likes_posts.include?(post)
  end
end