🥀

【Ruby on Rails】コメントへのいいね機能登録が、リロードすると解除されてしまうエラーを対処した

2024/08/17に公開

はじめに

現在Ruby on Railsでアプリ開発を行なっております。
その中でTurboStreamsを使用してコメントへのいいね機能を実装しております。
コメントへのいいね機能の実装方法は以前記事にもしておりましたが、その時には気づかなかったエラーが発生しておりました。
その内容が表題にある通り、コメントいいね登録後、リロードするといいねが勝手に解除されてしまうという内容です。

今回学んだこと、今後の反省点が浮き彫りになりましたので記事にしたいと思います。
コメントのいいね機能の詳細な実装方法は、こちらに記載ありますので参照していただけますと幸いです。

前提

  • こちらの記事で、コメントへのいいね機能の実装は解説しております。
  • 今回は表題のエラーの解消方法の記事になるので、テーブル名やファイルそれぞれの解説はいたしません。コードも変更したファイルのみ記載いたしますのでご了承ください。

今回のエラー発生原因

今回のエラー発生していた原因は、コントローラーからうまくインスタンス変数が渡されていなかったため発生していました。
なぜインスタンス変数が適切に渡されていなかったかというと、部分テンプレートを多用しすぎており、どこまでインスタンス変数がビュー内で渡されているか追えていないことが原因でした。

具体的には、①のファイルから④まで、部分テンプレートを呼び出し続けている状態でした。
①app/views/articles/show.html.erbで、コメントへのいいねを表示する部分テンプレートを呼び出し
②app/views/comments/_comment.html.erbで、コメントのいいね登録されたか、または解除されたかの条件分岐をしている部分テンプレートの呼び出し
③app/views/comments/_commentfavorite.html.erbでいいねが登録された時、いいねが解除された時のボタンのアイコン部分テンプレートの呼び出し
④app/views/comments/_favorite.html.erbと_unfavorite.html.erbで、登録と解除用アイコンの部分テンプレートを作成

上記から分かる通り、部分テンプレート内でまた部分テンプレートを呼び出していて、インスタンス変数がどこまで渡っているのかが分かりづらくなっていました。
また上記に関して、サーバーエラーが出ている訳でもなかったので、エラー解消までかなり時間を要してしまいました。

どのようにエラー解消したのか

今回どこまでインスタンス変数が渡されているのかが不鮮明になっていたので、①から順番にインスタンス変数がどこまで渡されているかを確認しました。
その中で、③のapp/views/comments/_commentfavorite.html.erbで、commentfavoriteのインスタンス変数が渡っていないことに気がつきました。

※下記が修正内容ですが今回ファイルを切り分けすぎたことを反省し、_commentfavorite.html.erbで実装していた内容を、②_comment.html.erbへ直接記載しました。

  • app/views/comments/_comment.html.erb
<% if logged_in? %>
        <% if comment.favorited?(current_user) %>
          <%= render 'comments/unfavorite', comment:,
                                            commentfavorite: comment.commentfavorites.find_by(user: current_user) %>
        <% else %>
          <%= render 'comments/favorite', comment: %>
        <% end %>
      <% else %>
        <%= link_to login_path, class: 'app-link' do %>
          <i class="bi bi-arrow-through-heart text-gray-600"></i>
          <%= comment.commentfavorites.count %>
        <% end %>
      <% end %>

いいねが登録されたとき、'comments/unfavorite'が呼び出されますが、そこでcommentfavorite: comment.commentfavorites.find_by(user: current_user)
がうまく受け渡されていなかったため、リロードするとコメントのいいねが解除されてしまいました。

本来であればコントローラーに書くべき内容ですが、一旦自分の理解のためにビューで処理を実装しています。

また、_comment.html.erbが呼び出している_unfavorite.html.erb内で、idをcomment.idからcommentfavorite.idに修正しています。

  • app/views/comments/_unfavorite.html.erb
<%= link_to commentfavorite_path(commentfavorite), data: { turbo_method: :delete }, id: "first-unfavorite-#{commentfavorite.id}",
                                                   class: 'app-link' do %>
  <i class="bi bi-arrow-through-heart-fill" style="color: rgb(20 184 166);"></i>
  <%= comment.commentfavorites.count %>
<% end %>
  • app/views/commentfavorites/destroy.turbo_stream.erb
    _unfavorite.html.erbのidをcomment.idからcommentfavorite.idに修正したため、destroy.turbo_stream.erbでもidを修正しました。
<%= turbo_stream.replace "first-unfavorite-#{@commentfavorite.id}" do %>
  <%= render 'comments/favorite', comment: @comment, commentfavorite: @commentfavorite %>
<% end %>

最後に

部分テンプレートは可読性を上げるために多用しておりましたが、今回のようなエラーを受け部分テンプレートを使用しすぎるのもよくないと強く感じました。
最後までご覧いただきありがとうございました。

Discussion