お気に入り機能の作成イメージ
今回はこのようなお気に入り機能の実装をしていきたいと思います。
(非同期通信は使用しないで作成しています)
前提
・deviseを導入している
(user_signed_in?メソッドを使う必要があるため)
・userモデル、お気に入り機能をつけたいモデルが存在している
(お気に入り機能をつけたいモデル → 今回はitemモデルで作成します)
作成手順
①お気に入り機能のモデルを作成する
・名前はお好きなものでOK
今回は「favorite」モデルで作成します。
他には「like」モデルで作成している例もあります。
(モデルは単数形で書くルールがありますので、単数形で作成しましょう)
rails g model favorite
以下の2つのファイルができたら成功です。
db/migrate/xxxx_create_favorites.rb
app/models/favorite.rb
↑ likeモデルにした場合は「favorite」が「like」になります。
②カラムを追加
class CreateFavorites < ActiveRecord::Migration[6.0]
def change
create_table :favorites do |t|
t.references :user, foreign_key: true #追記
t.references :item, foreign_key: true #追記
t.timestamps
t.index [:user_id, :item_id], unique: true #追記
end
end
end
【お気に入りの機能はユーザーと投稿がに紐づいている必要があるため以下を追加します】
・t.references :user, foreign_key: true
・t.references :item, foreign_key: true
↑ 2つ目は自分のアプリの投稿モデル(お気に入り機能をつけたいモデル)に変更しましょう
【同じユーザーが同じ投稿に対して、複数回いいね登録できないようにする設定を追加します】
・t.index [:user_id, :item_id], unique: true
rails db:migrate
上記の内容を更新し、データベース(シークエルPROなど)が作成されているか確認しましょう。
③モデルにアソシエーションの設定(3点)
class Favorite < ApplicationRecord
belongs_to :user
belongs_to :item
end
class User < ApplicationRecord
has_many :items
#お気に入り機能のアソシエーション処理
has_many :favorites, dependent: :destroy
end
class Item < ApplicationRecord
belongs_to :user
#お気に入り機能のアソシエーション処理
has_many :favorites, dependent: :destroy
end
favoriteモデルは中間テーブルとして作成していますが
「through:」表記なしでも実装可能でした。
④ルーティングの設定
お気に入り機能をつけたいコントローラーに「ネスト」の形で記述します。
! resourceメソッド(単数形)で記述します。
・・indexを除いたアクションのルーティングがid無しで生成されるようにするため
Rails.application.routes.draw do
devise_for :users
root to: "items#index"
resources :items do #こちらの2行を追加
resource :favorites, only: [:create, :destroy]
end
end
⑤コントローラー作成・記述
rails g controller favorites create destroy
class FavoritesController < ApplicationController
def create
@favorite = current_user.favorites.create(item_id: params[:item_id])
redirect_back(fallback_location: root_path )
end
def destroy
@item = Item.find(params[:item_id])
@favorite = current_user.favorites.find_by(item_id: @item.id)
@favorite.destroy
redirect_back(fallback_location: root_path )
end
end
内容
current_user.favorites.create(item_id: params[:item_id])
・・現在ログインしているユーザーがお気に入りした「投稿(item)のid」を保存する
redirect_back
・・お気に入りをしたページにリダイレクトする(非同期にしない場合実装)
(fallback_location: root_path )
・・万が一お気に入りをしたページに戻れない場合は、エラー回避のためトップページに遷移する
@item = Item.find(params[:item_id])
・・送られてきた(お気に入りされた)投稿のidを変数に代入、以下の行ではその変数を使用して削除を行っている
⑥ビューの作成
初めにビューで使用する自作のメソッドをuserモデルに作成します。
def favorited?(item)
self.favorites.exists?(item_id: item.id)
end
()内の引数が、お気に入りされているか・いないかを確認しています。
最終的なビューはこちら
・@items = Item.all (全ての投稿のデータを取得しています)
<% @search_item.each do |items| %>
<% if user_signed_in? %>
<% if current_user.favorited?(items) %>
<%= link_to item_favorites_path(items), method: :delete do %>
<span class="item__favorite">❤️</span>
<span class="favorite__count"><%= items.favorites.count %></span>
<% end %>
<% else %>
<%= link_to item_favorites_path(items), method: :post do %>
<span class="item__favorite">🤍</span>
<span class="favorite__count"><%= items.favorites.count %></span>
<% end %>
<% end %>
<% else %>
<%=link_to '🤍', new_user_session_path, class: :item__favorite%>
<% end %>
<% end %>
内容
(以下詳しい内容では、記述上「do」を抜いて説明しているものがありますので、以下の記述は参考までにご覧いただけますと幸いです)
<% if user_signed_in? %>
・・・A
<% else %>
・・・B
<% end %>
A・・いいねを押したり、外したりできる
B・・♡を押すとログインページへ遷移する(いいね機能は使えない)
・補足
Bのようにログインページや新規登録ページに遷移することで、「ログイン(新規登録)すると使えること」を感覚的に感じてもらいやすくなったり、登録ユーザーを増やすことにも繋がると思いましたので、今回はリンク先をこちらにしました。
「ユーザーがログインしていたら、Aの処理を実行する」
「ログインしていなければBの処理を実行する」という記述をすることで未ログイン時のエラー防ぐことができます。
こちらの記述をしていないと、未ログイン時にはこのようなエラーが出ました。
「current_userを指定しているけれど、そもそも誰もログインしていないよ!」と教えてくれています。
<% @items.each do |items| %>
<% if current_user.favorited?(items) %>
<%= link_to item_favorites_path(items), method: :delete %>
<% else %>
<%= link_to item_favorites_path(items), method: :post%>
<% end %>
<% end %>
<% end %>
if current_user.favorited?(items)
・・userモデルで作成したメソッドを使用して、「delete(いいねを外す)」か「post(いいねをつける)」か、どちらの条件に当てはまるかという記述をしています。今回(items)はeach文のブロック変数を使用しているためこのような記述になります。
詳細ページなど単体のデータを取り出したい場合は()内の変数を適切なものにすると表示されます!
<span class="favorite__count"><%= items.favorites.count %></span>
countをつけることで、お気に入りされた数が表示されます。
まとめ
今回は以下のようなお気に入り機能の作り方をまとめました。
うまく表示されず苦戦しましたが、動きをつけることができてよかったです。
非同期でできると利便性がさらに上がると思いますので、
気になる方はぜひ調べてみてください!
こちらの記事がどなたかの参考になりましたら嬉しいです。