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

##流れ

⑴表示されているメッセージの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',

//キーを自分で決め（今回はｌａｓｔ_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

//これにより５０００ミリ秒ごとに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/)){

```