#はじめに
ネットショッピングしてていいなと思った商品見つけたらお気に入り登録したことありますよね?
そのとき、画面が更新されずにお気に入りやいいねすると♡マークの色が変わったりしますよね。あとは、お気に入りした商品を一覧で確認できたらいいですよね。今回はその実装のメモ書きです。
※出品や投稿機能(itemsテーブル)及びログイン機能(usersテーブル)が備わっていることを前提にお話を進めます。
#実装の手順(同期編)
完成のイメージはクリックした時に画面の一部が更新されて数字のカウントが増えていく・・・みたいなイメージ。ついでに削除機能も搭載します。お気に入りに追加したものは一覧で確認できるページも作成しちゃいます。
まずは、itemsテーブルとusersテーブルの中間テーブルとして
likesテーブルを作成。
↓追加するカラムとアソシエーションはこんな感じ↓
itemsテーブル
Column | Type | Options |
---|---|---|
===略=== | ||
※追加なし※ |
Association
- has_many :likes
- has_many :liked_users, through: : likes, source: :user #お気に入一覧作りたい時使うが今回は使わない
###likesテーブル #中間テーブル
Column | Type | Options |
---|---|---|
item_id | integer | null: false |
user_id | integer | null: false |
Association
- belongs_to :item
- belongs_to :user
usersテーブル
Column | Type | Options |
---|---|---|
===略=== | ||
※追加なし※ |
Association
- has_many :likes
- has_many :liked_items, through: :likes, source: :item #お気に入一覧作りたい時使うが今回は使わない
これにてDB設計は完了
つづいてモデルの作成。以下のコマンドをターミナルに入力
rails g model like
テーブルを作成するためマイグレーションファイルを編集
class CreateLikes < ActiveRecord::Migration[5.2]
def change
create_table :likes do |t|
t.integer :item_id, null: false
t.integer :user_id, null: false
end
end
end
からのrails db:migrateします。
そしたらモデルが生成されるのでアソシエーションを書いていきます。
has_many :likes #追加
has_many :likes #追加
class Like < ApplicationRecord
belongs_to :item
belongs_to :user
validates :user_id, presence: true
validates :item_id, presence: true
validates_uniqueness_of :item_id, scope: :user_id
def self.like_method(item, user)
Like.find_by(item_id: item.id, user_id: user.id)
end
end
self.like_method(item, user)
ここでIF分の設定をしちゃいます。
likeテーブルにitem_idとuser_idに入ってるーーーって条件を設定します!
次にコントローラーを作成するため以下のコマンドを実行
rails g controller likes
無事にコントローラーが作成されたら、
・ビューファイル
・コントローラー
・ルーティング
それぞれ設定していきます。
ーー略ーー
resources :items, only: [:new, :create, :edit, :update, :show, :destroy] do
resources :likes, only: [:create, :destroy]
end
ーー略ーー
resources :users, only: [:show] do
resources :likes, only: [:index]
end
ーー略ーー
createとdestroyはitemsにネスト
indexはusersにネスト
class LikesController < ApplicationController
before_action :set_item, only: [:create, :destroy]
def index
@items = Item.includes(:item_images).order("created_at DESC")
end
def create
@like = Like.create(item_id: params[:item_id],user_id: current_user.id)
redirect_to item_path(@item.id)
end
def destroy
@like = Like.find_by(item_id: params[:item_id],user_id: current_user.id)
@like.destroy
redirect_to item_path(@item.id)
end
def set_item
@item = Item.find(params[:item_id])
end
end
createとdestroyはビューファイルがないのでリダイレクトの設定が必要になります。
ーー略ーー
- if user_signed_in? && Like.like_method(@item, current_user)
.check_btn__like--add{data: {item_id: @item.id}}
= link_to "/items/#{@item.id}/likes/:id" , method: :DELETE do
= icon( "fa", "star")
お気に入り
= @item.likes.length
- elsif user_signed_in?
.check_btn__like{data: {item_id: @item.id}}
= link_to "/items/#{@item.id}/likes", method: :POST do
= icon( "fa", "star")
お気に入り
= @item.likes.length
- else
.check_btn__like
= link_to new_user_session_path do
= icon( "fa", "star")
お気に入り
= @item.likes.length
ーー略ーー
お気に入り登録する時の画面はこちら
.mypage_Wrapper
%section.mypage_title
お気に入り一覧
%section.like_Wrapper
.like__box
- @items.each do |item|
- if user_signed_in? && Like.like_method(item, current_user)
.like__box__product
.like__image
= link_to item_path(item.id) do
= image_tag item.item_images[0].image.url
.like__name
= item.name
%ul
%li
= item.price.to_s
%li
= "円"
%li.like__tax
= "(税込)"
%li.like__icon
= link_to "/items/#{item.id}/likes/:id" , method: :DELETE do
= icon("fas", "star")
.bottom_Wrapper
これが、お気に入りした商品一覧で表示するもの
.like_Wrapper {
width: 100%;
}
.like__box {
background-color:white;
margin: 0 auto;
width: 65%;
display: flex;
justify-content: center;
flex-wrap: wrap;
&__product {
width: 180px;
height: 90%;
margin: 25px 2% 0;
transition: all .3s ease-in-out;
.like__image {
width: 180px;
height: 140px;
margin-bottom: 3%;
img{
width: 100%;
height: 100%;
object-fit: cover;
}
}
.like__name {
font-weight: bold;
}
ul{
display: flex;
font-size: 16px;
li{
font-weight: bold;
}
.like__tax {
font-size: 10px;
writing-mode: lr-tb;
width: 30px;
line-height: 30px;
margin-left: 2%;
margin-right: 24%;
}
.like__icon {
i {
font-size:1.1em;
color: orange;
}
}
}
}
&__product:hover {
cursor: pointer;
transform: scale(1.1, 1.1);
}
}
一応、CSSも
ここまでの実装で同期した状態で実装できるかと思います!
いったんここまで、Ajaxを利用した非同期通信を実装するとよりリッチになるのでそのことを書いて行けたらいいなと・・・
それはまた後日・・・
参考
https://techtechmedia.com/favorite-function-rails/#i
https://qiita.com/naberina/items/c6b5c8d7756cb882fb20
https://qiita.com/hisamura333/items/e3ea6ae549eb09b7efb9
https://qiita.com/shh-nkmr/items/48fe53282253d682ecb0