0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Rails】お気に入り登録とお気に入りした一覧を表示する巻

Last updated at Posted at 2020-10-18

#はじめに

ネットショッピングしてていいなと思った商品見つけたらお気に入り登録したことありますよね?
そのとき、画面が更新されずにお気に入りやいいねすると♡マークの色が変わったりしますよね。あとは、お気に入りした商品を一覧で確認できたらいいですよね。今回はその実装のメモ書きです。

※出品や投稿機能(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

テーブルを作成するためマイグレーションファイルを編集

2XXXXXXXXXXXX5_create_likes.rb
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します。
そしたらモデルが生成されるのでアソシエーションを書いていきます。

user.rb
has_many :likes #追加
item.ruby
has_many :likes #追加
like.rb
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

無事にコントローラーが作成されたら、
・ビューファイル
・コントローラー
・ルーティング
それぞれ設定していきます。

routes.rb
ーー略ーー  
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にネスト

likes_controller.rb
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はビューファイルがないのでリダイレクトの設定が必要になります。

index.html.haml
ーー略ーー  
      - 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
ーー略ーー  

お気に入り登録する時の画面はこちら

index.html.haml
.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.scss
.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を利用した非同期通信を実装するとよりリッチになるのでそのことを書いて行けたらいいなと・・・
それはまた後日・・・

Image from Gyazo

Image from Gyazo

参考

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?