チーム開発 いいね機能実装 商品詳細ページ
仕様の確認
1.商品のお気に入り登録ができる(商品詳細ページ、ログイン時のみ)
2.お気に入りにした商品を閲覧できる(マイページ)
3.商品一覧に反映(TOPページ)
本日実装したのは、1.です。
実装
1.モデル作成
[ターミナル] $ rails g model Like user:references product:references
2.モデル編集
[product.rb] has_many :likes, dependent: :destroy def like_user(user_id) likes.find_by(user_id: user_id) end [user.rb] has_many :likes, dependent: :destroy [like.rb] belongs_to :user belongs_to :product, counter_cache: :likes_count
dependent: :destroy モデルのインスタンスが削除された際に、関連したlikeも削除
like_userメソッドは、そのユーザーが持っているlikeモデルを探す
counter_cache: :likes_count カウントを作成してくれる
3.Productsテーブルにカラムの追加
[terminal] $ rails g migration AddNumcountToProduct likes_count:integer $ rails db:migrate
4.route.rb編集
resources :products do resources :likes, only: [:create, :destroy] end
5.コントローラー作成
[terminal] rails g controller Likes create destroy
6.コントローラー編集
class LikesController < ApplicationController before_action :set_product def create @like = Like.create(user_id: current_user.id, product_id: params[:product_id]) @likes = Like.where(product_id: params[:product_id]) @product.reload end def destroy like = Like.find_by(user_id: current_user.id, product_id: params[:product_id]) like.destroy @likes = Like.where(product_id: params[:product_id]) @product.reload end private def set_product @product = product.find(params[:product_id]) end end
7.ビュー作成
[likes/_like.html.haml] - if Like.find_by(user_id: current_user.id, product_id: product.id) = link_to product_like_path(product_id: product.id, id: product.likes[0].id), method: :delete, remote: true do .like-btn__wrapper %i.fas.fa-star %p お気に入り %p = product.likes_count - else = link_to product_likes_path(product), method: :post, remote: true do .like-btn__wrapper %i.far.fa-star %p お気に入り %p = product.likes_count
[XXX.html.haml] # ーーー表示箇所ーーー %div{id: "like-#{@product.id}", class: "like-btn"} = render "likes/like", product: @product
8.JS作成
[views > likes > create.js.haml] $("#like-#{@product.id}").html("#{j(render partial: 'like', locals: { product: @product })}"); [views > likes > destroy.js.haml] $("#like-#{@product.id}").html("#{j(render partial: 'like', locals: { product: @product })}");
haml形式で記述しました。
躓き
migrationエラーが発生
rails aborted! StandardError: An error has occurred, all later migrations canceled: Column `user_id` on table `likes` does not match column `id` on `users`, which has type `int(11)`. To resolve this issue, change the type of the `user_id` column on `likes` to be :integer. (For example `t.integer :user_id`). Original message: Mysql2::Error: Cannot add foreign key constraint: CREATE TABLE `likes` (`id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY, `user_id` bigint, `product_id` bigint, `created_at` datetime NOT NULL, `updated_at` datetime NOT ULL, INDEX `index_likes_on_user_id` (`user_id`), INDEX `index_likes_on_product_id` (`product_id`), CONSTRAINT `fk_rails_1e09b5dabf`
「外部キーに設定するUserモデルのIDの型がinteger型になっていて合わないよ。」
「bigint型にすれば解決できるよ。」と怒られました。
▶︎これはActiveRecordのバージョンが問題でした。
既存ファイルがActiveRecord::Migration[5.0]に対し、なぜか作成されたファイルは[5.2]だった。
テーブルのIDカラムのデフォルトの型が、以下の通り変更となっているようでした。
rails 5.0 : integer
rails 5.2 : bigint
バージョンを変更し、解決しました。
参考:https://qiita.com/igat/items/4c29ab388b817b01daf8
挙動が起きない。
ボタンを押しても反応しない。
・まずJSを外して上手くいくか → ダメ
・JSを外すとエラーが表示された為、viewからcontrollerへと遡ってチェック。
▶︎結果、controllerのインスタンス作成の記述が間違っていました。
@product = product.XXX になっていた。
@product = Product.XXX に修正して解決。
今回一気にまとめて記述し、途中でviewの確認を行わなかった為、問題が複雑化した気がします。
今後の実装はなるべく小さいタームで確認を行い、デバッグのスピードをあげていきたいと思います。
missing a templateエラー
上記修正後に出たエラー。
▶︎サーバーの再起動ができていなかったことが原因でした。
サーバーの再起動をし、解決。
最後にCSSを調整して本日の実装は完了しました。