【rails】いいね機能【初心者プログラミング】

手書き風のハートの素材になります。イラレでライン画としてつくりました。ラインをなるべく手で描いたような軌跡でなんじゅうにもえがくことでおしゃれなつくりになればよいと思ってつくりしました。  | ハートフレーム, ハート 素材, ハートの壁紙

railsでいいね機能を実装!!

前提

・ユーザー情報がある(Userモデルがある)

・投稿機能がある(今回は本の投稿機能(book)があります)

 

流れ

①モデル作成(Favorite)

②ルーティング

③アソシエーション

④コントローラ作成(favorites)

⑤ビュー

 

いいね機能の実装

①モデル作成(Favorite)

いいねの情報を保存するモデルを作成


$ rails g model Favorite

カラムを作成

 db/migrate/日付_create_favorites.rb 

class CreateFavorites < ActiveRecord::Migration[5.2]
  def change
    create_table :favorites do |t|
      
      t.references :user, foreign_key:true
      t.references :book, foreign_key:true

      t.timestamps
    end
  end
end
reference型

外部キー制約をするために使用!
なぜ
→他のテーブルに格納されている値だけに限定することで親テーブルと子テーブルの整合性がとれる

references型を使うメリット
・userではなくuser_idというカラム名を作成してくれる
・インデックスを自動で貼ってくれる
※t.references :user だけでは外部キー制約はつかない
foreign_key:true を記述!

 

カラム名 データ型 カラムの説明
id (自動生成) integer いいねごとのID
user_id integer(references) いいねしたユーザのID
book_id integer(references) いいねされた投稿画像のID

テーブルを確定!


$ rails db:migrate

 

②ルーティング

ユーザーがURLにアクセスした時に、
どのコントローラのどのアクションに処理を振り分けるかを定義

 config/routes.rb 

Rails.application.routes.draw do
 devise_for :users
 root 'homes#top'
 resources :users
 resources :books do
    resource :favorites, only: [:create, :destroy]  //createとdestroyのみ使用
  end
 end

booksのルーティングにネストする
ネストすることで...
どの本に結びついたいいね(favorites)なのかURLで判断することが可能に!

$ rails routes 確認
book_favorites DELETE /books/:book_id/favorites(.:format) favorites#destroy
       POST /books/:book_id/favorites(.:format) favorites#create

※このbook_idparams[:book_id]で取得できる

 

③アソシエーション

関連する「favorite」「book」「user」のモデルファイルに関係性を記述

 app/models/favorite.rb 

  class Favorite < ApplicationRecord
 
    belongs_to :user  //1つのユーザーを持つ
    belongs_to :book  //1つの本を持つ

    validates_uniqueness_of :book_id, scope: :user_id //1人1いいねのみ
   
  end
validates

保存する時には、値が正しいかどうか確かめてくれる

「uniqueness」同一データは一つのみ許可する

 

 app/models/book.rb 

  class Book < ApplicationRecord
  
    belongs_to :user  //1つのユーザーを持つ
    has_many :favorites,dependent: :destroy  //複数のいいねを持つ
  end
>

dependent: :destroy
bookの情報が削除された時に結びついているいいねも削除される

 

 app/models/user.rb 

  class User < ApplicationRecord
  
    has_many :books, dependent: :destroy  //複数の本を持つ
    has_many :favorites, dependent: :destroy  //複数の本を持つ
    
   //fovoritesの中にbook.idが存在する情報はあるか
    def favorited_by?(book)
      favorites.where(book_id: book.id).exists?
    end
    
  end
④コントローラ作成(favorites)

$ rails g controller Favorites

 

アクションを追加
(「いいねする」と「いいね外す」のみなのでcreate と destroyのみ)

 app/controllers/favorites_controller.rb 

class FavoritesController < ApplicationController
  def create
  //book_idを取得
    book = Book.find(params[:book_id])
 //現在のユーザーのいいねにbookのidを新しく入れる
    favorite = current_user.favorites.new(book_id: book.id)
Favoriteテーブル user_id book_id
id (自動生成) curent_user book.id
それぞれ取得した数字が入る

 //favorite(表のデータ↑)を保存
    favorite.save
 //元のを再度読み込む→いいねされたページを開くことができる
    redirect_back(fallback_location: root_path)
  end

  def destroy
    book = Book.find(params[:book_id])
 //現在のユーザーのいいねをbookのidから見つけ出す
    favorite = current_user.favorites.find_by(book_id: book.id)
 //bookを削除
    favorite.destroy
    redirect_back(fallback_location: root_path)
  end
 end
⑤ビュー

「いいなする」時と「いいね外す」時の画面表示を記述

 app/views/books/index.html.erb 

 //user.rbで定義した"favorited_by?(book)"で現在のユーザーがいいねしているか確認
<% if current_user.favorited_by?(recipe) %>
 <%= link_to recipe_favorites_path(recipe),method: :delete do %>
  ♡
 <% end %>
<% else%>
 <%= link_to recipe_favorites_path(recipe),method: :post do %>
  ❤︎
 <% end %>
<% end %>
<%= recipe.favorites.count %>