いいねの削除機能実装するときはmethod: :deleteにする必要があった話

こんにちは!kossyです!


いいね周り実装する時に、
めっちゃハマったのでブログに残したいと思います。。。



話を簡潔にするために一部ロジックを省いて記載しています。











前提情報


User, Product, Likeというモデル定義で、

User has_many products
User has_many likes
Product has_many likes

という構成にしていました。

また、投稿詳細画面からいいねの登録、削除ができるように実装しました。


いいね周りのコードは、

config/routes.rb

Rails.application.routes.draw do
  devise_for :users

  post "likes/:product_id/create" => "likes#create"
  post "likes/:product_id/destroy" => "likes#destroy"

  resources :products, only: [:show]
end


/views/products/show.html.haml

  = link_to("お気に入りから削除", "/likes/#{@product.id}/destroy", method: :post)
  = link_to("お気に入り登録", "/likes/#{@product.id}/create", method: :post)


/controller/products_controller.rb

  def show
    @product = Product.find(params[:id])
  end


/controller/likes_controller.rb

  def create
    @like = current_user.likes.build(product_id: params[:product_id])
    if @like.save
      redirect_to product_path(@like.product_id)
    else
      flash[:notice] = "お気に入りの登録に失敗しました"
    end
  end

  def destroy
    like = current_user.likes.find_by(product_id: params[:product_id])
    if like.destroy
      redirect_to likes_user_path(current_user)
    else
      flash[:notice] = "お気に入りの削除に失敗しました"
    end
  end

という感じにしていました。











リファクタリング


ここでメンターさんから、
「resourcesを使って実装しましょう」と指令が出たため、

routes.rb

Rails.application.routes.draw do
  devise_for :users

  resources :products, only: [:show] do
    resources :likes, only: [:create, :destroy]
  end
end

/views/products/show.html.haml

= link_to("お気に入りから削除", product_like_path(@product), method: :post)
= link_to("お気に入り登録", product_likes_path(@product), method: :post)

という記述に変更。
これで大丈夫かと思ってました。









しかし、、、


ここで動作確認をしたところ、
いいねの登録はできたものの、削除になると、

localhost:3000/products/1/likes/1

Routing Error
No route matches [POST] "/products/1/likes/1"

と怒られてしまいました。
likesのidが正しく取得できていないと思い、
ローカル変数としてlikeを定義し、pathの引数にlikeを入れて再チャレンジしたものの、

localhost:3000/products/1/likes/10


Routing Error
No route matches [POST] "/products/1/likes/10"

と怒られてしまいました。









rails routesちゃんと見ようね。


likesの値は取得できているのになんで削除できないんだろうと考え、
method: :postとなっていた部分をmethod: :deleteに変えたところ、
ようやく削除に成功しました。。。

rails routesで確認すると、

product_likes POST   /products/:product_id/likes(.:format)     likes#create
product_like DELETE /products/:product_id/likes/:id(.:format) likes#destroy

ちゃんとDELETEを指定しろって書いてありました。。。









みなさん絶対マネしちゃダメ


このようなくだらないミスをする人を一人でも減らすために本エントリを書きました。
みなさん、いいねの削除機能を実装するときはmethod: :deleteにするのを忘れないようにしましょう(棒)