【Rails×Ajax】いいね機能の実装で上手く出来ないあなたへの2つの注意喚起 #学習者向け
目的
はじめまして。
今回、Railsでいいね機能をQiita等の記事通りに行っても上手く行かない!という方へ向けた、ちょっとした実装の際のチェック項目を列挙させていただきます。
前提条件
対象となる読者
- 「いいね機能」の実装において、railsの同期処理では問題なく処理されるが、Ajax通信が上手く行かない
開発環境
- ruby 2.5.1
- Rails 5.2.4.1
- mysql Ver 14.14
実装済み機能
- 同期処理で「いいね機能」が正しく処理されていること
筆者が参考にした記事
- 「いいね機能」同期処理編
【初心者向け】丁寧すぎるRails『アソシエーション』チュートリアル【幾ら何でも】【完璧にわかる】🎸
- 「いいね機能」非同期処理編 【Rails×Ajax】いいね機能ハンズオン #学習者向け#Ajax
Ajax処理のいいね機能の実装方法のチェック項目
ずばり、先に結論をここで提示させていただきます
1. 部分テンプレートの呼び出しが正しく相対パスで指定されているか
2. インスタンス変数の指定がfavorites_controller.rb
で指定されているか
の2点です。では、詳しく見ていきましょう。
1. 部分テンプレートの呼び出しが正しく相対パスで指定されているか
よく陥りがちなミスの一つですね。実際にどのように間違えて実装しどの様なエラー文が出たのでしょうか?
.btn-bar
.btn-box
= render partial: "favorite_ajax", locals: { item: @item }
-# view/items/_favorite_ajax.html.hamlでいいねボタンを部分テンプレートを作成した
- if user_signed_in? -# ユーザーがログインしているか判断
- if item.favorited_by?(current_user) -# ログイン中のユーザーがいいねしているかしていないかを判断
= link_to item_favorites_path(item.id), method: :delete, class: "favorite red", remote: true do -# リクエストをjs形式で送信
= icon('fas', 'heart')
いいね!
= item.favorites.count
- else
= link_to item_favorites_path(item.id), method: :post, class: "favorite", remote: true do -# リクエストをjs形式で送信
= icon('far', 'heart')
いいね!
= item.favorites.count
- else
= link_to new_user_session_path, class: "favorite", remote: false do -# リクエストをhtml形式で送信
= icon('far', 'heart')
いいね!
= item.favorites.count
$('.btn-box').html("#{escape_javascript(render partial: "favorite_ajax", locals: { item: @item })}");
-# この記述ではview/favorites/_favorite_ajax.html.hamlを呼び出していることとなる。従って、対応するファイルが無いことからTemplate::Error(Missing partial)が発生
$('.btn-box').html("#{escape_javascript(render partial: "favorite_ajax", locals: { item: @item })}");
-# この記述ではview/favorites/_favorite_ajax.html.hamlを呼び出していることとなる。従って、対応するファイルが無いことからTemplate::Error(Missing partial)が発生
items_controller.rb
のshowアクションのビューでいいね機能の実装をしています。また、いいね機能のDBへの保存・削除はfavorites_controller.rb
のcreateアクション・destroyアクションで実装をしています。
今回、いいねボタンを押した際にビューが切り替わる部分をview/items/_favorite_ajax.html.haml
で切り出し部分テンプレートを作成しました。ajaxではview/favorites/create.js.haml
, view/favorites/destroy.js.haml
をそれぞれ用意し、view/items/_favorite_ajax.html.haml
を呼び出したかったのですが、相対パスの指定が誤っていました。以下のように修正するとTemplate::Error(Missing partial)
は解消されます。
$('.btn-box').html("#{escape_javascript(render partial: "items/favorite_ajax", locals: { item: @item })}");
-# partial: にitems/ を追加
$('.btn-box').html("#{escape_javascript(render partial: "items/favorite_ajax", locals: { item: @item })}");
-# partial: にitems/ を追加
2. インスタンス変数の指定がfavorites_controller.rbで指定されているか
こちらはまず、どんなエラー文が出たか確認して見ましょう
renderの中身のitem.favorited_by?
に対して
undefined method `favorited_by?' for nil:NilClass
とエラーが出ています。ここでいうitemとはitems_controller.rb
のshowアクションで定義されているインスタンス変数@itemをrenderの中身ではitemとして記述している、という意味です。favorited_by?
については、item.rb
で事前に定義した「ログイン中のユーザーがいいねしているかしていないかを判断」するメソッドです。
class Item < ApplicationRecord
# (中略)
def favorited_by?(user)
favorites.where(user_id: user.id).exists?
end
end
このことから、
render内ではitem.favorited_by?
が定義されていない
→ render内ではitem
そのものが定義されていない
→ view/favorites/destroy.js.haml
では、@itemが定義されていない
→ favorites_controller.rb
では、@itemが定義されていない!!
ということが判明しました。確認してみると確かにfavorites_controller.rb
では、@itemが定義されていなかったので、以下のように記述を加えたところ、正しくAjax処理が実行されました。
(items_controller.rb
でも同様のset_itemメソッドを定義済みです)
class FavoritesController < ApplicationController
before_action :authenticate_user!
# 追記==========================================================================
before_action :set_item
# ==============================================================================
def create
favorite = current_user.favorites.build(item_id: params[:item_id])
if favorite.save
else
flash.now[:alert] = favorite.errors.full_messages
end
end
def destroy
favorite = Favorite.find_by(item_id: params[:item_id], user_id: current_user.id)
if favorite.destroy
else
flash.now[:alert] = '削除できませんでした。'
end
end
private
# 追記==========================================================================
def set_item
@item = Item.find(params[:item_id])
end
# ==============================================================================
end
まとめ
いかがだったでしょうか。
いいね機能のAjaxは、実装の手順そのものはすごくシンプルです。しかし、いいね機能専用のビューを用意していなかったり、部分テンプレートの保存場所の違いによって記述内容が異なるケースがあります。当たり前のことではあるのですが、記事通り実装してみて上手く出来なかった時、解決の一助となれば幸いです。
※私自身初めてのQiitaの投稿です!
ご指摘等ございましたらコメントにてお待ちしております。
Author And Source
この問題について(【Rails×Ajax】いいね機能の実装で上手く出来ないあなたへの2つの注意喚起 #学習者向け), 我々は、より多くの情報をここで見つけました https://qiita.com/shoji621/items/ab017566b6d8b9708171著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .