No_ideaのわからん日和

✏️...プログラミングが全然出来ない奴がわからんわからん言いながら様々な構文(記述方法やエラー構文など)と奮闘しながら成長していく成長記録です🐢

Ruby on Rails: チャットメッセージ実装(自動更新機能まで)...chapter18-2

タイムゾーンの設定

2020年9月1日みたいな感じで投稿した日にちを表示したいのでタイムゾーンを設定していきます。

config/application.rb

module Rensyu1
 class Application < Rails::Application
  # Initialize configuration defaults for originally generated Rails version.
  config.load_defaults 6.0

  # Settings in config/environments/* take precedence over those specified here.
  # Application configuration can go into files in config/initializers
  # -- all .rb files in that directory are automatically loaded after loading
  # the framework and any gems in your application.
  config.time_zone = "Tokyo"
  config.active_record.default_timezone = :local
end

config.time_zone= "Tokyo"

config.active_record.default_timezone= :localを設定します。

$rails s

サーバーを再起動します。

https://techacademy.jp/magazine/22191#:~:text=%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%BE%E3%83%BC%E3%83%B3%E3%81%A8%E3%81%84%E3%81%86%E3%81%AE%E3%81%AF,%E3%81%8C%E3%81%9A%E3%82%8C%E3%81%9F%E3%82%8A%E3%81%97%E3%81%BE%E3%81%99%E3%80%82

 

 

 

②chat_messages_controller.rbの編集

app/controllers/chat_messages_controller.rb

def index
 @group = ChatGroup.find(params[:chat_group_id])
 @messages = ChatGroup.find(params[:chat_group_id]).chat_messages
end

@messagesにチャットグループでのメッセージを代入します。

 

 

③index.html.erbのビューを編集

https://gyazo.com/6781ccd0fa45a0b85d1f9b21fe9567f7

https://gyazo.com/89f484d0508d9edd20bf7de4dd206382

https://gyazo.com/0c6b1342f1c00691713c797fcafa2d7b

https://gyazo.com/7dd81829b992ee348ce8fd6122b89ce6

とりあえずメッセージが投稿されるようになりました。

しかし非同期通信はできていないので、投稿したときに

非同期通信をして部分的更新をして更新速度を上げるのと、2窓してみて自動更新できるようにしていきたいと思います。

 

④app/controllers/api/chat_messages_controller.rbを作成

$rails g controller api/chat_messages

https://gyazo.com/4eb0e8e76d30d2989d0adf1bbbbc99e1

class Api::ChatMessagesController < ApplicationController
end

これでApplicationControllerはApi::ChatMessagesControllerを継承できるようになりました。

これで、このコントローラーへコードしたことはapiを使用したもののみを対応させて動かすことができます。

後でここに投稿した後に投稿されたメッセージが表示されるように処理内容をコードします。

 

 

 

④create.json.jbuilder

app/views/chat_messages/create.json.jbuilder

json.id @conversations.id
json.user_icon @conversations.user.user_icon.url
json.message @conversations.message
json.image @conversations.image.url
json.date @conversations.created_at.strftime("%Y年%m月%d日")
json.updated_at @conversations.updated_at

app/controllers/chat_messages_controller.rbのcreateアクションでインスタンス変数へ代入したメッセージ情報をjsonへ変換します。

 

 

 

⑤index.json.jbuilder

app/views/api/chat_messages/index.json.jbuilder

json.array! @messages do |chat_message|
 json.id chat_message.id
 json.user_icon chat_message.user.user_icon.url
 json.message chat_message.message
 json.image chat_message.image.url
 json.date chat_message.created_at.strftime("%Y年%m月%d日")
 json.updated_at chat_message.updated_at
end

 忘れないようにこちらのjbuilderファイルも作成しておきましょう。

私はこのファイルを作成し忘れていて配列を用意したいのにできず2日悩みました。←慣れていれば、こんなことで悩むことはないと思うのですが😂 (笑)

 

 

 

⑥app/controllers/api/chat_messages_controller.rbを編集

class Api::ChatMessagesController < ApplicationController
 def index
  @group = ChatGroup.find(params[:chat_group_id])
  @messages = @group.chat_messages.includes(:user).where('id > ?', params[:id])
  respond_to do |format|
   format.html
   format.json
  end
 end
end

@groupのインスタンスへChatGroupモデルを通してfindメソッドでchat_group_idを探してきて、投稿しているチャットグループの情報を代入します。

@messages = @group.chat_messages.includes(:user).where('id > ?, params[:id]')

params[:id]...これはchat_messages.jsでajaxによって送られてきたidです。

チャットメッセージで最後に投稿されたメッセージのidよりも大きいidのメッセージがないか探してきてインスタンス変数@messagesへ代入します。

 

includes(:user)はN+1問題の対策のために使用します。

N+1問題を解決する理由としては同じ繰り返し処理を減らしてSQL発行を減らそうという考えです。

このincludesがなければ、「投稿されたメッセージは誰のなの???」とchatmessagesテーブルとusersテーブルの間を行ったり来たりして探すという作業が行われます。

なので投稿されたメッセージ分だけusersテーブルを行き来します。

これは無駄な作業です。

これではメッセージが増えれば増えるほどSQLへの負担が大きくなります。

投稿されたメッセージをまとめてusersテーブルへ探しに行けるのがincludesメソッドです。

https://qiita.com/TsubasaTakagi/items/8c3f4317ad917924b860

 

そしてrespond_to do |format|~endまででhtmlをjsonへ変換できるようにしておきます。

 

 

 

⑦chat_messages.jsファイルを作成

app/javascript下へchat_messages.jsファイルを作成します。

 

 

  

⑧app/javascript/packs/application.jsを編集

chat_messages.jsファイルを使用できるように↓を追加します。

require("chat_messages.js")

これでchat_messages.jsファイルを使用できるようになりました。

 

 

 

⑨app/controllers/chat_messages_controller.rbを編集

def create
 @conversations = ChatMessage.new(messages_params)
 if @conversations.save
  respond_to do |format|
   format.html
   format.json
  end
 end
end
 

createメソッドでjsonへ変換できるようにしておきます。

 

 

 

⑩app/javascript/chat_messages.jsを編集

注意することは、⑥でparams[:id]としたこと。

これは$.ajax({ ~ }).done({ ~ data: {id: 〇〇})←この太字にした部分と同じでないといけません。

なのでdata:{last_id: 〇〇}とした場合、⑥はparams[:last_id]とします。

[ 1 ]

 https://gyazo.com/99ef582eb08084f5ddb789763fa700c1

[ 2 ]

https://gyazo.com/a48a1d2c55da565e1158f03380732abc

[ 3 ]

https://gyazo.com/5e6ae49f2ca2da5dd68a189d152f501c

[ 1 ]でここでメッセージを投稿した時に、追加するhtmlを作っておきます。

・変数message_idに投稿されたメッセージのidを格納

・変数user_iconにもしユーザーアイコンがあるならばアイコンを、なければデフォルトのアイコンを格納

・変数chat_messageにメッセージがあるなら格納し、なければ入れない。

・変数imageもchat_messageと同様。画像があるかないかによって処理を分けてます。

・変数dateへupdated_atを格納

・変数htmlへ投稿したときの追加内容を格納

[ 2 ]でメッセージ投稿処理をしています。

・e.preventDefault()で投稿ボタンを押すまで処理を待ってくれます。

https://qiita.com/tochiji/items/4e9e64cabc0a1cd7a1ae

・変数formDataへformタグの開始から終了までの処理内容を入れてインスタンス変数を格納

・変数urlにメッセージページのurlを格納

・done(function(data){・・・})でdataは投稿された内容を格納しています。これを結果で返します。

$('form')[0].reset();...これでメッセージを投稿後リセットされます。

https://pikawaka.com/javascript/form-reset

$('#chat-messages-btn').prop('disabled', false);...ボタンが再度有効になります。

https://qiita.com/pugiemonn/items/5db6fb8fd8a303406b17

 

・変数iへ送ったメッセージが表示されているトップの座標を格納

・$('html, body').animate({scrollTop:i})...animateメソッドを使用しスクロール動作できるようにします。その際、垂直にスクロールしたいのでscrollTopを使用し垂直にスクロールするためのピクセル数を取得します。

https://itsakura.com/jquery-scroll

https://www.sejuku.net/blog/61689

[ 3 ]でメッセージを最新状態に保つための処理をしています。

・変数last_message_idに最新の(最後の)メッセージidを取得。

・if文内容でこのメッセージページと一致した場合にこの中の処理が実行できるようにします。このif文がないと他のチャットグループのメッセージを開いているとエラーがでます。

・変数insertHTMLへ空の変数を定義

・messages.forEach(function(message){})...messagesをforEachで繰り返しし取り出し処理して、この中での処理内容を引数messageへ渡します。

・insertHTML=buildHTML(message);...投稿されたメッセージ結果を格納

・$('.chat-messages__conversations').append(insertHTML);...insertHTMLに格納された処理内容を<div class="chat-messages__conversations">~</div>へ追加。

・setIntervalは一定の処理を繰り返すメソッドです。これで、自動更新機能を実装できます。7000は一定処理を繰り返す時間を設定しています(今回は7000ミリ秒=7秒間隔で処理しています)。

https://techacademy.jp/magazine/5537

 

[ 1 ]でのreturn htmlに関しては、これをコードしておかないと追加できなくなります。

returnは関数処理した結果を戻り値として返せます。

https://www.javadrive.jp/javascript/function/index4.html

https://gyazo.com/6704d1f3533a3d085fd1db3fd78cfa17

https://gyazo.com/7ef7c0e2efc4a874c12fcf0d6a36028d

 

 

 

 

 

非同期機能と自動更新機能を実装しました。

実装時のポイントはconsole.logを使用して処理内容を確認しながら作るってことでしょうか😅(例)console.log(this);)。

 

 

 

 

 

 

 

 

以上です。