ChatSpace自動更新実装

最初に行っておきますが、今回初投稿です。
それとプログラム自体、初めて1ヶ月くらいなので文言的に絶対におかしいところはあると思いますｗ
それを承知の上でアウトプットしようと思ったので、もし何か言いたいことがあれば遠慮なく言ってください！

では本題！！！

今回現在作成中の簡易版のツイートアプリに自動更新機能を実装したので、それを紹介したいと思います。

https://gyazo.com/53a4b6702ec2fa4bb4c61269cda34a43

↑このGIFみたいに２画面同じブラウザ開いて片方更新したらこう片方に最新メッセージが反映されればOK！
（GIFの埋め込み方わかりませんでした😂）

■WEBAPIを実装するため専用のフォルダやファイルを作成
※ファイル名APIに注意！
app/controllers/api/messages_controller.rb
app/views/api/messages/index.json.jbuilder

■data()メソッドで最新メッセージのidを取得するため、メッセージを出力するViewにカスタムデータ属性を付与。

```javascript:_message.html.haml
.message{"data-message-id": "#{message.id}"}//jbuilderで記載したmessage.idが使えるようカスタムデータ属性を付与。
  .upper-message
    .upper-message__user-name
      = message.user.name
    .upper-message__date
      = message.created_at.strftime("%Y/%m/%d %H:%M")
  .lower-meesage
    - if message.content.present?
      %p.lower-message__content
        = message.content
    = image_tag message.image.url, class: 'lower-message__image' if message.image.present?
```


■ｍessage.jsに自動更新の記述を行う。

```javascript:message.js
$(function () {
  
  function buildHTML(message) {

    image = (message.image) ? `<img class= "lower-message__image" src=${message.image} >` : ""; //三項演算子を使ってmessage.imageにtrueならHTML要素、faiseなら空の値を代入。
    
    var 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-meesage">
            <p class="lower-message__content">
              ${message.content}
            </p>
            ${image}
          </div>
        </div>`
    return html;
  }
  ・・・インクリメンタルサーチの記述・・・
  }) 
  // 自動更新はここから。 
  var reloadMessages = function () {
    if (window.location.href.match(/\/groups\/\d+\/messages/)){//今いるページのリンクが/groups/グループID/messagesのパスとマッチすれば以下を実行。
      var last_message_id = $('.message:last').data("message-id"); //dataメソッドで.messageにある:last最後のカスタムデータ属性を取得しlast_message_idに代入。
      // var group_id = $(".group").data("group-id");

      $.ajax({ //ajax通信で以下のことを行う
        url: "api/messages", //サーバを指定。今回はapi/message_controllerに処理を飛ばす
        type: 'get', //メソッドを指定
        dataType: 'json', //データはjson形式
        data: {last_id: last_message_id} //飛ばすデータは先ほど取得したlast_message_id。またparamsとして渡すためlast_idとする。
      })
      .done(function (messages) { //通信成功したら、controllerから受け取ったデータ（messages)を引数にとって以下のことを行う
        var insertHTML = '';//追加するHTMLの入れ物を作る
        messages.forEach(function (message) {//配列messagesの中身一つ一つを取り出し、HTMLに変換したものを入れ物に足し合わせる
          insertHTML = buildHTML(message); //メッセージが入ったHTMLを取得
          $('.messages').append(insertHTML);//メッセージを追加
        })
        $('.messages').animate({scrollTop: $('.messages')[0].scrollHeight}, 'fast');//最新のメッセージが一番下に表示されようにスクロールする。
      })
      .fail(function () {
        alert('自動更新に失敗しました');//ダメだったらアラートを出す
      });
    }
  };
  setInterval(reloadMessages, 5000);//5000ミリ秒ごとにreloadMessagesという関数を実行し自動更新を行う。
  });
});
```

■ルーティンとコントローラjbuilderの編集

```ruby:app/controllers/api/messages_controller.rb
class Api::MessagesController < ApplicationController
  def index
    @group = Group.find(params[:group_id]) #今いるグループの情報をパラムスの値を元にDBから取得。
    @messages = @group.messages.includes(:user).where('id > ?', params[:last_id]) #グループが所有しているメッセージの中から、params[:last_id]よりも大きいidがないかMessageから検索して、@messagesに代入。
  end
end
```

```ruby: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 #APIのコントローラを動かすための記述
      resources :messages, only: :index, defaults: { format: 'json' } #defaultsオプションを利用して、このルーティングが来たらjson形式でレスポンスするよう指定。
    end
  end
end
```

```javascript:index.json.jbuilder
json.array! @messages do |message|
  json.content      message.content
  json.image        message.image.url
  json.date         message.created_at.strftime("%Y/%m/%d %H:%M")
  json.user_name    message.user.name
  json.id           message.id
end
```

■コントローラのアクションへのURLパターンができるので、コンソールで確認。

```console:console
rake routes | grep api

$ rake routes | grep api

group_api_messages GET    /groups/:group_id/api/messages(.:format) api/messages#index {:format=>"json"}
```

とりあえずこれで自動更新はできるようになりました。
まだまだ足りないところがたくさんありますが、参考にしてください。
また何か文言がおかしいとか、こうした方がいいとかあれば遠慮なく行ってください！
今後も投稿続けようかと思います！