LoginSignup
8
17

More than 3 years have passed since last update.

chat-space自動更新機能の実装

Last updated at Posted at 2019-11-07

流れ

⑴表示されているメッセージのHTMLにid情報を追加
⑵メッセージを更新するためのアクションを実装
⑶追加したアクションを動かすためのルーティングを実装
⑷追加したアクションをリクエストするよう実装
⑸取得した最新のメッセージをブラウザのメッセージ一覧に追加
⑹数秒ごとにリクエストするよう実装
⑺メッセージ分だけスクロールするよう実装
⑻メッセージ一覧のページでのみJSが動くよう実装

⑴表示されているメッセージのHTMLにid情報を追加

_message.html.haml


//メッセージ全体にidを付与。   ※#{message.id}はjbuilderファイルで定義している
.message{"data-message-id": "#{message.id}"}

⑵メッセージを更新するためのアクションを実装

コントローラーのapiディレクトリの中に、messages_controller.rbを作成

messages.controller.rb
#APIの中にありますよーって意味
class Api::MessagesController < ApplicationController

  def index

#今いるグループの情報をparamsによって取得し変数@groupに代入
    @group = Group.find(params[:group_id]) 

#グループ内のメッセージでlast_idよりも大きいidのメッセージがないかを探してきてそれらを@messageに代入
    @messages = @group.messages.includes(:user).where('id > ?', params[:last_id])
  end
end

⑶追加したアクションを動かすためのルーティングを実装

ルーティングの追加

routes.rb
Rails.application.routes.draw do
  devise_for :users
  root 'groups#index'
  resources :users, only: [:index, :edit, :update]
  resources :groups, only: [:new, :create, :edit, :update] do
    resources :messages, only: [:index, :create]
#ここからが追加
    namespace :api do
      resources :messages, only: :index, defaults: { format: 'json' }
    end
  end
end

jbuilderファイルも作成

index.json.jbuilder

json.array! @messages do |message|
  json.content message.content
  json.image message.image
  json.created_at message.created_at
  json.user_name message.user.name
  json.id message.id
end

⑷追加したアクションをリクエストするよう実装

message.js

//自動更新用の関数定義
let reloadMessages = function () {

//ブラウザに表示されている最後のメッセージからidを取得して、変数に代入
      let last_message_id = $('.message:last').data("message-id");

//ajaxの処理   
      $.ajax({

//今回はapiのmessagesコントローラーに飛ばす
        url: "api/messages",
//HTTP_メソッド
        type: 'get',
//データはjson型で
        dataType: 'json',

//キーを自分で決め(今回はlast_id)そこに先ほど定義したlast_message_idを代入。これはコントローラーのparamsで取得される。
        data: {last_id: last_message_id} 
      })

//doneの処理(仮)
    .done(function(messages) {
    console.log('success');
  })

//failの処理(仮)
    .fail(function() {
      console.log('error');
  });
};

⑸取得した最新のメッセージをブラウザのメッセージ一覧に追加

doneの中身の編集

message.js

.done(function (messages) { 

//追加するhtmlの入れ物をつくる
      let insertHTML = '';

//取得したメッセージたちをEach文で分解
      messages.forEach(function (message) {

//htmlを作り出して、それを変数に代入(作り出す処理は非同期の時に作った)
        insertHTML = buildHTML(message); 

//変数に代入されたhtmlをmessagesクラスにぶち込む
        $('.messages').append(insertHTML);
      })
    })

buildHTMLを一部編集

message.js

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

//messageクラスにdata-message-idを付与
    let html = `<div class="message", data-message-id="${message.id}">


                    <div class="upper-message">
                      <div class="upper-message__user-name">
                      ${message.user_name}
                      </div>
                      <div class="upper-message__date">
                      ${message.date}
                      </div>
                    </div>
                    <div class="lower-message">
                      <p class="lower-message__content">
                      ${message.content}
                      </p>
                      ${image}
                    </div>
                  </div> `
  $('.messages').append(html);
  }

⑹数秒ごとにリクエストするよう実装

message.js

//これにより5000ミリ秒ごとにreloadMessagesが呼び出される※処理の外に記述
setInterval(reloadMessages, 5000);

⑺メッセージ分だけスクロールするよう実装

message.js

//doneの処理内に記述。非同期の方でも定義しているので、関数にしてまとめた方がなお良い
$('.messages').animate({scrollTop: $('.messages')[0].scrollHeight}, 'fast');

⑻メッセージ一覧のページでのみJSが動くよう実装

if文で関数を挟む

message.js

//今いるページのリンクが/groups/グループID/messagesのパスとマッチすれば実行
if (window.location.href.match(/\/groups\/\d+\/messages/)){

8
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
17