質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.78%

ajax(非同期通信)の実装において、「いいね」ボタンを押してもjavascriptが反映されない

受付中

回答 0

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 171

skem

score 1

TwitterのようなSNSアプリを作成しています。railsでjavascriptを書いて「いいね」を非同期通信にしたいのですが、下記のコードを書いて、画面上で「いいね」ボタンを押しても「いいね」が反映されません。ただ、HTML/CSSは記述できているため、リロードすると反映されます。

viewファイル
renderから部分テンプレートを使っています。

        .like
          %div{:id => "likes_buttons_#{m.id}"}
            = render partial: 'likes/like', locals: { m: m}


likes/_like.html.haml

- if current_user.already_like_this?(m)
  - like = current_user.likes.find_by(message_id: m.id)
  = link_to user_message_like_path(current_user.id,m.id,like.id), method: :delete, remote: true do
    %i.fas.fa-heart.unlike-btn
- else
  = link_to user_message_likes_path(current_user.id,m.id), method: :post, remote: true do
    %i.far.fa-heart.like-btn


【likesコントローラー】

class LikesController < ApplicationController
  def create
    unless current_user.already_like_this?(clicked_message)
      @like = current_user.like_this(clicked_message)
      flash[:success] = '投稿に「いいね!」しました。'
      if @like.save
        respond_to :js
      end
    end
  end

  def destroy
    @like = current_user.likes.find_by(message_id: params[:message_id]).destroy
    flash[:danger] = '「いいね!」を解除しました。'
    if @like.destroy
      respond_to :js
    end
  end

  private

  def clicked_message
    Message.find(params[:message_id])
  end

end


【create.js.erb】

$('#likes_buttons_<%= @like.id %>').
  html("<%= j(render partial: 'likes/like', locals: {m: @like}) %>");


【ターミナル】
「いいね」を押した時に、ターミナル上では下記のように出ているので、JSファイルが送られていると思うのですが。。

Started POST "/users/1/messages/140/likes" for ::1 at 2020-10-16 11:47:34 +0900
Processing by LikesController#create as JS
  Parameters: {"user_id"=>"1", "message_id"=>"140"}
  User Load (0.3ms)  SELECT  `users`.* FROM `users` WHERE `users`.`id` = 1 ORDER BY `users`.`id` ASC LIMIT 1
  Message Load (0.2ms)  SELECT  `messages`.* FROM `messages` WHERE `messages`.`id` = 140 LIMIT 1
  Message Exists (0.2ms)  SELECT  1 AS one FROM `messages` INNER JOIN `likes` ON `messages`.`id` = `likes`.`message_id` WHERE `likes`.`user_id` = 1 AND `messages`.`id` = 140 LIMIT 1
  CACHE (0.0ms)  SELECT  `messages`.* FROM `messages` WHERE `messages`.`id` = 140 LIMIT 1  [["id", 140], ["LIMIT", 1]]
  Like Load (0.2ms)  SELECT  `likes`.* FROM `likes` WHERE `likes`.`user_id` = 1 AND `likes`.`message_id` = 140 LIMIT 1
   (0.2ms)  BEGIN
  Message Load (0.2ms)  SELECT  `messages`.* FROM `messages` WHERE `messages`.`id` = 140 LIMIT 1
  Like Exists (0.2ms)  SELECT  1 AS one FROM `likes` WHERE `likes`.`message_id` = 140 AND `likes`.`user_id` = 1 LIMIT 1
  SQL (1.7ms)  INSERT INTO `likes` (`message_id`, `user_id`, `created_at`, `updated_at`) VALUES (140, 1, '2020-10-16 02:47:34', '2020-10-16 02:47:34')
   (0.4ms)  COMMIT
   (0.1ms)  BEGIN
  Like Exists (1.0ms)  SELECT  1 AS one FROM `likes` WHERE `likes`.`message_id` = 140 AND (`likes`.`id` != 378) AND `likes`.`user_id` = 1 LIMIT 1
   (0.1ms)  COMMIT
  Rendering likes/create.js.erb
  Rendered likes/_like.html.haml (2.2ms)
  Rendered likes/create.js.erb (4.9ms)
Completed 200 OK in 39ms (Views: 18.0ms | ActiveRecord: 4.9ms)

ご助言頂ければ幸いです。

【10/17 実施事項追記】

他の記事に「idを統一する」と書かれていたので確認した所、
viewファイルが下記"likes_buttons_#{m.id}"で、

.like
  %div{:id => "likes_buttons_#{m.id}"}
    = render partial: 'likes/like', locals: { m: m}


create.js.erbが下記'#likes_buttons_<%= @like.id %>'のようになっていたので、

$('#likes_buttons_<%= @like.id %>').
  html("<%= j(render partial: 'likes/like', locals: {m: @like}) %>");


create.js.erbのidを以下'#likes_buttons_<%= m.id %>'のように書き換えました。

$('#likes_buttons_<%= m.id %>').
  html("<%= j(render partial: 'likes/like', locals: {m: @like}) %>");

改めて「いいね」ボタンを押すと、今度はconsoleで以下のように出て、
イメージ説明

ターミナルでは下記のように出ました。

ActionView::Template::Error (undefined local variable or method `m' for #<#<Class:0x00007fb36301dab0>:0x00007fb3742adfd0>):
    1: $('#likes_buttons_<%= m.id %>').
    2:   html("<%= j(render partial: 'likes/like', locals: {m: @like}) %>");

なので今度は、
viewファイルのidを、"likes_buttons_#{@message.id}"
create.js.erbのidを、'#likes_buttons_<%= @message.id %>'
と書き換えました。

再々度「いいね」ボタンでチャレンジすると、ターミナルのエラーが下記に変わりました(consoleは上記同様のエラー)。

ActionView::Template::Error (undefined method `id' for nil:NilClass):
    1: $('#likes_buttons_<%= @message.id %>').
    2:   html("<%= j(render partial: 'likes/like', locals: {m: @like}) %>");

create.js.erbのlocals: {m: @like}が間違っている気もするので、調べてみたいと思います。

ご指摘等ございましたら、よろしくお願い致します。

【10/21 実施事項追記】

idを変えるとエラーが出るので、当初のコード(【10/17 実施事項追記】より以前)に戻しました。

この状態で「いいね」(または、いいね解除)を押すと、リアルタイムでは反映されないのですが、

  • google chromeのconsole上でエラーは出ていない
  • リロードしたら正しく反映される
  • ターミナルを確認するとjsファイルが送られている履歴

上記3点からJS側で何らかの通信設定が原因かと思います。

「いいね」以外にメッセージ投稿機能を設置している(こちらは正常にajaxが機能する)のですが、
下記ファイルとの兼ね合いで何か原因があるのか?

app/assets/javascripts/comment.js

$(function(){

  function buildHTML(j){
    if ( j.content ) {
      var html =
       `<div class="message">
          <div class="takerface">
            <img src=${"https://imgc.eximg.jp/i=https%253A%252F%252Fs.eximg.jp%252Fexnews%252Ffeed%252FRen_ai%252FRen_ai_188420_6aed_1.jpg,zoom=600,quality=70,type=jpg"} >
          </div>
          <div class="contents">
            <div class="takername">
              ${j.user_name + " さんへ"}
            </div>
            <div class="letter">
              <p class="lower-message__content">
                ${j.content}
              </p>
            </div>
            <div class="credo">
              #仕事好き #親身心 #人生を変える
            </div>

            <div class="like">
              <a href="users/${j.user_id}/messages/${j.message_id}/likes" data-method="post">
                <i class="far fa-heart like-btn">
                </i>
              </a>
              ${j.like_count}
            </div>
          </div>

          <div class="message__date">
            ${j.created_at}
          </div>
          <div class="more">
            <ul class="more_list">
              <li>
                <a href="users/${j.user_id}/messages/${j.message_id}/edit">編集</a>
              </li>
              <li>
                <a href="users/${j.user_id}/messages/${j.message_id}" data-method="delete">削除</a>
              </li>
            </ul>
          </div>
        </div>`
      return html;
    }
  }

  $('#new_message').on('submit', function(e){
    e.preventDefault();
    var formData = new FormData(this);
    var url = $(this).attr('action');

    $.ajax({
      url: url,  //同期通信でいう『パス』
      type: 'POST',  //同期通信でいう『HTTPメソッド』
      data: formData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })

    .done(function(data){
      var html = buildHTML(data);
      $('.messages').append(html);
      $('form')[0].reset();
      $('.messages').animate({ scrollTop: $('.messages')[0].scrollHeight});
      $(".form__submit").removeAttr("disabled");
    })

    .fail(function() {
      alert("メッセージ送信に失敗しました");
    });

  })
});

着目すべき視点等ご共有頂ければ幸いです。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正の依頼

  • hatsu

    2020/10/17 00:33

    consoleエラーとかって出ていたりしますでしょうか?
    また2個目のコードブロックがlikes/like.html.hamlでしょうか?

    キャンセル

  • skem

    2020/10/17 10:18 編集

    ・「いいね(orいいね解除)」を押しても、Googleの検証では、consoleエラーは出ていない状態です。
    →idを統一した所、上記のようにconsoleエラーが出るようになりました。

    ・はい、2個目のコードブロックはlikes/like.html.hamlです。質問内容に追記しておきました。

    キャンセル

まだ回答がついていません

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.78%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る