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("メッセージ送信に失敗しました"); }); }) });
着目すべき視点等ご共有頂ければ幸いです。
あなたの回答
tips
プレビュー