LoginSignup
2
4

More than 3 years have passed since last update.

Railsで「いいね!」機能を作る - ③「いいね!」を解除できるようにする

Last updated at Posted at 2020-09-02

ここまでの前提/今回のゴール

さて、初学者向けのテキストを噛み砕いて解いてみるシリーズ、第3段となりました。
ここまでは、Twitterのようなアプリで、投稿に「いいね!」機能をつけることを目標に、以下のような手順でコードを書いてきました。

Railsで「いいね!」機能を作る - ①アソシエーションに別名をつける
Railsで「いいね!」機能を作る - ②「いいね!」のcreateアクション

今回は、これらをさらに一歩進めて「いいね!」した投稿の「いいね!」を解除する機能を作ろうと思います。

Image from Gyazo

ユーザーが投稿した内容について、ボタンを押すごとに「いいね!」と「いいね!解除」が切り替わり「いいね!」とそれをやめることができる仕様にしたいと思います。

View

今回はビューから実装をスタートします。
ビューはこんな感じで作成しました。

views/posts/_post.erb
<!-- postsのインスタンスは、パーシャルに渡されている前提です。 -->
<% posts.each do |post| %>
  <div>
    <!-- 投稿者名・投稿日時・投稿内容 -->
    <div>
      <%= post.user.name %> posted at <%= post.created_at %>
    </div>
    <div>
      <p><%= post.content %></p>
    </div>

    <!-- いいね!ボタン -->
    <div>
      <!-- すでに「いいね!」されている時の表示 -->
      <% if current_user.favorites.include?(post) %>     
        <%= form_with(model: @like, url: like_path(id: post.id), local: true, method: :delete) do |f| %>
          <%= f.hidden_field :post_id, value: post.id %>
          <%= f.submit 'いいね!解除' %>
        <% end %>
      <% else %>

     <!-- まだ「いいね!」していない時の表示 -->
        <%= form_with(model: @like, url: likes_path, local: true) do |f| %>
          <%= f.hidden_field :post_id, value: post.id %>
          <%= f.submit 'いいね!' %>
        <% end %>
      <% end %>      
    </div>
  </div>
<% end %>

一つ目のポイントですが、form_with(model: @like, url: ...)の部分では、model: Likeではなく、model: @likeを使わないとダメでした。

なぜかなと思いapiドキュメントを調べてみたものの、ここだけは解決せず。

ただ、こちらの記事によると「隠しフィールドでデータを送りたいときは@like」ということだそうなので、今回はここまでの理解でませることにします。

form_with(model: @like) do |f|の形で、Railsは自動でリクエストの送信先URLを推測してくれますが、今回は、デフォルトのURLではエラーが出るので、url:オプションでリクエストの送信先を指定します。

また、url: like_path(id: post.id)でクリックした投稿のidがリクエストのparamsに含まれていることにも注目してください。

最後に、local: trueでajaxではない通信を指定し、method: :deleteでDELETEメソッドでRailsにリクエストを送信することを記載しています。

Controller

コントローラーの記載はこんな感じです。

class LikesController < ApplicationController

  def create
    current_user.like_this(clicked_post)
    flash[:success] = '投稿に「いいね!」しました。'
    redirect_back(fallback_location: root_path)
    # 前回の記事からelse以下の記述は削除
  end

  # ↓前回の記事からここを追記!
  def destroy
    current_user.likes.find_by(post_id: params[:post_id]).destroy
    flash[:danger] = '「いいね!」を解除しました。'
    redirect_back(fallback_location: root_path)
  end

  private

  def clicked_post
    Post.find(params[:post_id])
  end
end

まず、destroyアクションは、current_user.likes.find_by(post_id: params[:micropost_id]).destroyで現在のユーザーの「いいね!」した投稿の中にクリックした投稿が含まれているか確認します。

クリックした投稿のidはparams[:post_id]の形で取り出すことができます。(さっきurl: like_path(id: post.id)の形で送りましたね!)
そして、投稿を見つけたらdestroyをします。

上記で、destroyアクションが実装できたので、createアクションの記述も少し書き換えます。さらに不要になったコードは消しておきます。

以上で、いいね!/いいね解除機能の実装は完了です:relaxed:
@likeの構造だけ説明がつかなかったのが残念ですが、これで自信を持って説明できそうです:relieved:

余裕があれば、これをさらに応用してユーザーのフォロー/フォロー解除機能も実装し、詳しく読み解いていきたいです。

ここまで読んでくだっさった皆様、ありがとうございました^^

追記

2020.09.29 一部メソッドをリファクタリングしました

その他

応用編で、こんなものも作りました。

RailsでAjaxで「いいね!」機能を実装する。

2
4
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
2
4