【Rails×Ajax】좋아 기능의 실장으로 잘 할 수 없는 당신에게의 2개의 주의 환기 #학습자용

목적



만나서 반갑습니다.
이번, Rails에서 좋아 기능을 Qiita 등의 기사대로 가도 잘 가지 않는다! 라는 분을 향한, 약간의 실장시의 체크 항목을 열거하겠습니다.

전제 조건



대상 독자


  • "좋아하는 기능"의 구현에서 rails의 동기화 처리는 문제없이 처리되지만 Ajax 통신은 잘 수행되지 않습니다

  • 개발 환경


  • 루비 2.5.1
  • Rails 5.2.4.1
  • mysql Ver 14.14

  • 구현된 기능


  • 동기화 프로세스가 "좋아하는 기능"을 올바르게 처리했음

  • 필자가 참고로 한 기사


  • 「좋아 기능」동기 처리편
    【초보자용】 너무 정중한 Rails 『연결』 튜토리얼
  • "좋아하는 기능"비동기 처리 편 【Rails×Ajax】좋아 기능 핸즈온 #학습자용#Ajax

  • Ajax 처리의 좋아하는 기능의 구현 방법의 체크 항목



    앞으로 결론을 여기서 제시하겠습니다.

    1. 부분 템플릿 호출이 올바르게 상대 경로로 지정되었는지



    2. 인스턴스 변수 지정이 favorites_controller.rb에 지정되어 있습니까?



    의 2점입니다. 그럼 자세히 살펴 보겠습니다.

    1. 부분 템플릿 호출이 올바르게 상대 경로로 지정되었는지



    잘 빠지기 쉬운 실수 중 하나입니다. 실제로 어떻게 실수로 구현하고 어떤 에러문이 나왔을까요?

    view/items/show.html.haml
    .btn-bar
      .btn-box
        = render partial: "favorite_ajax", locals: { item: @item }
    -# view/items/_favorite_ajax.html.hamlでいいねボタンを部分テンプレートを作成した
    
    

    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
    

    view/favorites/create.js.haml(실패 예)
    $('.btn-box').html("#{escape_javascript(render partial: "favorite_ajax", locals: { item: @item })}");
    -# この記述ではview/favorites/_favorite_ajax.html.hamlを呼び出していることとなる。従って、対応するファイルが無いことからTemplate::Error(Missing partial)が発生
    

    view/favorites/destroy.js.haml(실패 예)
    $('.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/favorites/create.js.haml
    $('.btn-box').html("#{escape_javascript(render partial: "items/favorite_ajax", locals: { item: @item })}");
    -# partial: にitems/ を追加
    

    view/favorites/destroy.js.haml
    $('.btn-box').html("#{escape_javascript(render partial: "items/favorite_ajax", locals: { item: @item })}");
    -# partial: にitems/ を追加
    

    2. 인스턴스 변수 지정이 favorities_controller.rb에 지정되어 있습니까?



    여기는 먼저 어떤 오류 문장이 나왔는지 확인합시다.

    render 내용 view/items/_favorite_ajax.html.haml 반대
    undefined method `favorited_by?' for nil:NilClass
    

    그리고 오류가 발생합니다. 여기서 말하는 item이란, Template::Error(Missing partial) 의 show 액션으로 정의되고 있는 인스턴스 변수 @item 를 render 의 내용에서는 item 으로서 기술하고 있다, 의 의미입니다. item.favorited_by? 에 대해서는, items_controller.rb 로 사전에 정의한 「로그인중의 유저가 좋아하는지 하고 있는지를 판단」하는 메소드입니다.

    models/item.rb
    class Item < ApplicationRecord
    # (中略)
      def favorited_by?(user)
        favorites.where(user_id: user.id).exists?
      end
    end
    

    이것으로부터,
    render내에서는 favorited_by? 가 정의되어 있지 않다
    → render내에서는 item.rb 그 자체가 정의되어 있지 않다
    item.favorited_by? 에서는, @item 가 정의되어 있지 않다
    item 그럼, @item 가 정의되어 있지 않다!!

    라는 것이 판명되었습니다. 확인해 보면 확실히 view/favorites/destroy.js.haml 에서는, @item 가 정의되어 있지 않았으므로, 이하와 같이 기술을 더했더니, 올바르게 Ajax 처리가 실행되었습니다.
    ( favorites_controller.rb 하지만 비슷한 set_item 메소드를 정의했습니다)

    favorites_controller.rb
    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의 투고입니다!
    지적 등이 있으면 코멘트에서 기다리고 있습니다.

    좋은 웹페이지 즐겨찾기