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

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

ただいまの
回答率

88.63%

Ajaxを用いた非同期通信によるチャット機能実装時エラー発生に関する質問(新規投稿の内容が別ウインドウに反映されない。)

解決済

回答 1

投稿

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

前提・実現したいこと

Ruby on rails/Ajax/JQuery

現在、チャット機能を持ったアプリ作成に伴い、Ajaxを使用した自動更新を実装しようとしております。
その際に以下のエラーが発生してしまっており、自身で色々と情報収集・確認しておりましたが、解決しなかったため、質問させていただきたく存じます。

実装したい内容:チャット機能+Ajaxを用いた非同期通信によるページの更新。

情報など不足しておりましたら、コメントいただけますと幸いです。
該当githubリポジトリ:https://github.com/Tatsu88-Tokyo/BulkFriends2

発生している問題・エラーメッセージ

エラー内容:新規投稿時、投稿した内容が非同期で更新されない。
(投稿しているページは反映されているが、他のウィンドウでその内容が反映されない)
エラーメッセージ:なし

該当のソースコード

:route
  resources :user, only: [:show, :edit, :update]do
    member do
      get 'profile'
      patch 'profile_update'
      get 'logout'
      get 'friends'
      get 'search'
      get :following, :followers
        resources :messages, only: [:index, :create]
        namespace :api do
          resources :messages, only: :index, defaults: { format: 'json' }
        end
    end
  end
:views/messages/index

=render "home/header_login"
.messages
  .messages__side
    .messages__side__header
      Messages
    .messages__side__contents
      %ul.message-friends
        %li.message-friends-list
          -@friends.each do |friend|
            .message-friend__line
              .line-message-name
                = link_to messages_path(friend),"data-turbolinks": false do
                  =friend.nickname
                  =link_to '詳細', user_path(friend),class:"detail"
  .messages__main
    .messages__main__header
      =@user.nickname
    .messages__main__contents
      .contents
        =render @messages
    .messages__main__footer
      .messages__main__footer__form
        = form_with model: @message,id: "new_message", local:true,"data-turbolinks": false do |f|
          = f.text_field :content, class: 'form__message', placeholder: 'type a message'
          .form__mask
            = f.label :image, class: 'form__mask__image' do
              %i.fas.fa-image.fa-2x
              = f.file_field :image, class: 'hidden'
          = f.submit 'Send', id: "msgbtn", class: 'form__submit'
:views/messages/_message

.message{data: {message: {id: message.id}}}
  .upper-message
    .upper-message__user-name
      = message.user.nickname
    .upper-message__date
      = message.created_at.strftime("%Y年%m月%d日 %H時%M分")
  .lower-message
    - if message.content.present?
      %p.lower-message__content
        = message.content
    = image_tag message.image.url, class: 'lower-message__image' if message.image.present?
:controllers/message
class MessagesController < ApplicationController
  before_action :set_user
  before_action :set_friend

def index
  send_ids = current_user.messages.where(receive_user_id: @user.id).pluck(:id)
  receive_ids = @user.messages.where(receive_user_id: current_user.id).pluck(:id)
  @message=Message.new
  @messages = Message.where(id: send_ids + receive_ids).order(created_at: :asc)
end

def create
  @message = current_user.messages.new(message_params)
  @message.receive_user_id = @user.id
  if @message.save
    respond_to do |format|
      format.html{ redirect_to messages_path(@user)}
      format.json
    end
  else
    @messages = @user.messages.includes(:user)
    flash.now[:alert] = 'メッセージを入力してください。'
    redirect_to messages_path(@user)
  end
end


private

def set_user
  @user = User.find(params[:id])
end

def set_friend
  @friends = current_user.matchers
end

def message_params
  params.require(:message).permit(:content, :image).merge(user_id: current_user.id)
end

end
:controllers/api/messages
class Api::MessagesController < ApplicationController
  def index
    @text = Message.where(user_id:current_user,receive_user_id:params[:id])
    last_message_id = @text.ids.last
    @content = @text.find(last_message_id)
    user = User.find(@content.user_id)
    @messages = user.messages.where(user_id:current_user,receive_user_id:params[:id]).where("id > ?", last_message_id)
  end
end

以下、console.logでlast_message_idをチェックしていたところ、新規投稿をしたページは、その投稿がlast_message_idとなっておりましたが、投稿をしていない別ウインドウでは投稿前のidがlast_message_idとなってしまっております。

:message.js
$(function(){
  let reloadMessages = function(){
    if (location.href.match(/\/user\/\d+\/messages/)){
      let last_message_id = $('.message:last').data('message-id');
      console.log(last_message_id);
    $.ajax({
      url:'api/messages',
      type:'get',
      dataType:'json',
      data: {id: last_message_id}
    })
    .done(function (messages){
      let insertHTML = '';
      messages.forEach(function (message){
      insertHTML = buildHTML(message);
      $('.contents').append(insertHTML);
      })
      $('.messages__main__contents').animate({scrollTop: $('.contents')[0].scrollHeight});
    })
    .fail(function(){
      alert('自動更新,失敗')
    });
    }
  };

setInterval(reloadMessages, 3000);

  function buildHTML(message){
    let image = message.image ? `<img class="lower-message__image" src=${message.image}>` : ``

    let html = `<div class="message" data-message-id = ${message.id}>
                <div class="upper-message">
                <div class="upper-message__user-name">
                ${message.name}
                </div>
                <div class="upper-message__date">
                ${message.created_at}
                </div>
                </div>
                <div class="lower-message">
                <p class="lower-message__content">
                ${message.content}
                </p>
                ${image}
                </div>
                </div>`;
      return html
    }
  $('#new_message').on('submit',function(e){
    e.preventDefault();
    let formData = new FormData(this);
    let url = $(this).attr('action');
    $.ajax({
      url: url,
      type:"POST",
      data: formData,
      dataType: 'json',
      processData: false,
      contentType:false
    })
    .done(function(message){
      let html = buildHTML(message)
      $('.contents').append(html);
      $('.messages__main__contents').animate({scrollTop: $('.contents')[0].scrollHeight});
      $('#new_message')[0].reset();
      $('.form__submit').prop('disabled',false);
    })
    .fail(function(){
      alert('error!');
    })
  })
});
:views/api/index.json.jbuilder
json.array! @messages do |message|
  json.content message.content
  json.name user.nickname
  json.image message.image.url
  json.created_at message.created_at.strftime("%Y年%m月%d日 %H時%M分")
  json.id message.id
end
:views/messages/create.json.jbuilder
json.name       current_user.nickname
json.content    @message.content
json.image      @message.image.url
json.created_at @message.created_at.strftime("%Y年%m月%d日 %H時%M分")
json.id @message.id

以上
何卒よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

check解決した方法

0

API/messageコントローラーの記述における取得したメッセージの中から最も新しいメッセージの取得ができていませんでした。
そのため、以下のように記述を修正して、解決することができました。

class Api::MessagesController < ApplicationController
  def index
    text = Message.where(user_id:current_user,receive_user_id:params[:id])
    # ajaxで送られてくる最後のメッセージのid番号を変数に代入
    last_message_id = params[:last_id]
    # 取得したメッセージ達から、idがlast_message_idよりも新しい(大きい)メッセージ達のみを取得
    @messages = text.includes(:user).where("id > ?", last_message_id)
  end
end

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

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

関連した質問

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

  • トップ
  • Ruby on Railsに関する質問
  • Ajaxを用いた非同期通信によるチャット機能実装時エラー発生に関する質問(新規投稿の内容が別ウインドウに反映されない。)