2回目の投稿になります。前回投稿した自動更新機能の実装に引き続き、おかしなところや間違った解釈をしている箇所があるかと思います。何かありましたら指摘いただけると助かります。
では本題
今回紹介するのはメッセージ送信機能の非同期通信化
こちらもchat-spaceに実装した機能です。
始めに手順です#
①.フォームが送信されたら、イベントが発火するようにする。
②.①のイベントが発火したときにAjaxを使用して、messagesコントローラのcreateアクションが動くようにする。
③.messagesコントローラのcreateアクションでメッセージを保存し、respond_toを使用してHTMLとJSONの場合で処理を分ける。
④.jbuilderを使用して、作成したメッセージをJSON形式で返す。
⑤.返ってきたJSONをdoneメソッドで受取り、HTMLを作成する。
⑥.⑤で作成したHTMLをメッセージ画面の一番下に追加する。
⑦.メッセージを送信したとき、メッセージ画面を最下部にスクロールする。
⑧.連続で送信ボタンを押せるようにする。
⑨.非同期に失敗した場合の処理を準備する。
今回編集するファイルはこちら#
◆message.js
◆app/controllers/messages_controller.rb
◆app/views/messages/create.json.jbuilder
では1つずつ紹介していきます#
①.フォームが送信されたら、イベントが発火するようにする。###
$(function(){
$('#new_message').on('submit', function(e){
e.preventDefault()
});
});
e.preventDefault()の記述でデフォルトのイベントを止めることができます。(フォームが送信された時にリダイレクトしないようにします)
②.①のイベントが発火したときにAjaxを使用して、messagesコントローラのcreateアクションが動くようにする。###
$(function(){
$('#new_message').on('submit', function(e){
e.preventDefault();
var formData = new FormData(this);//formdata変数の定義
var url = $(this).attr('action')//url変数の定義
$.ajax({
url: url,//パス
type: "POST",//HTTPメソッド
data: formData,
dataType: 'json',
processData: false,
contentType: false
})
});
});
$(this)=>form要素自体
attrメソッド==引数に指定した属性の値を取得することができます。引数に'action'を指定しているので、form要素のaction属性の値が取得できます。
③.messagesコントローラのcreateアクションでメッセージを保存し、respond_toを使用してHTMLとJSONの場合で処理を分ける。###
def create
@message = @group.messages.new(message_params)
if @message.save #投稿できたとき
respond_to do |format|
format.html { redirect_to group_messages_path(@group), notice: 'メッセージが送信されました' } #HTML形式のリクエストに対してのレスポンス
format.json #json形式のリクエストに対してのレスポンス(この後create.json.jbuilderに遷移される)
end
else
@messages = @group.messages.includes(:user)
flash.now[:alert] = 'メッセージを入力してください。'
render :index
end
end
④.jbuilderを使用して、作成したメッセージをJSON形式で返す。###
json.user_name @message.user.name
json.created_at @message.created_at.strftime("%Y年%m月%d日 %H時%M分")
json.content @message.content
json.image @message.image_url
必要な情報をjson形式に置き換えます。
⑤.返ってきたJSONをdoneメソッドで受取り、HTMLを作成する。(HTMLの名前は人によって異なると思います。ご自身のHTMLに合わせて修正をお願いします。)###
$(function(){
function buildHTML(message){
image = ( message.image ) ? `<img class="lower-message__image" src=${message.image} >` : ""; //三項演算子
var html = //変数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>`
return html; //return文
};
}
$('#new_message').on('submit', function(e){
e.preventDefault();
var formData = new FormData(this);
var url = $(this).attr('action')
$.ajax({
url: url,
type: "POST",
data: formData,
dataType: 'json',
processData: false,
contentType: false
})
.done(function(data){ //非同期通信の結果として返ってくるデータが引数(data)に入る
var html = buildHTML(data); //return文の戻り先で、完成したHTMLを受け取る
})
})
});
⑥.⑤で作成したHTMLをメッセージ画面の一番下に追加する。###
$('#new_message').on('submit', function(e){
e.preventDefault();
var formData = new FormData(this);
var url = $(this).attr('action')
$.ajax({
url: url,
type: "POST",
data: formData,
dataType: 'json',
processData: false,
contentType: false
})
.done(function(data){
var html = buildHTML(data);
$('.messages').append(html);
$("form")[0].reset(); //form内を空にする記述
受け取ったHTMLをappendメソッドで.messages(クラス)の一番最後に追加する。
⑦.メッセージを送信したとき、メッセージ画面を最下部にスクロールする。###
$('.messages').animate({scrollTop: $('.messages')[0].scrollHeight}, 50);
続きに記述します。末尾の50はアニメーションのスピードです。この場合50ミリ秒(0.05秒)で動きます。
⑧.連続で送信ボタンを押せるようにする。###
$('input').prop('disabled', false);
この記述を追加します。仕様によって一度投稿をすると送信ボタンが押せなくなってしまうため、この設定をキャンセルします。
⑨.非同期に失敗した場合の処理を準備する。###
.fail(function() {
alert("メッセージ送信に失敗しました");
});
});
この記述を追加します。
これで終了です。
問題なく動いてくれると思います。こちらも何かの役に立てることができれば幸いです。
また何か情報を発信することができたらいいなと思います
では最後に今回編集したコードを記述しておきます。
$(function(){
function buildHTML(message){
image = ( message.image ) ? `<img class="lower-message__image" src=${message.image} >` : ""; //三項演算子
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-message">
<p class="lower-message__content">
${message.content}
</p>
${image}
</div>
</div>`
return html;
}
$('#new_message').on('submit', function(e){
e.preventDefault();
var formData = new FormData(this);
var url = $(this).attr('action')
$.ajax({
url: url,
type: "POST",
data: formData,
dataType: 'json',
processData: false,
contentType: false
})
.done(function(data){
var html = buildHTML(data);
$('.messages').append(html);
$("form")[0].reset();
$('input').prop('disabled', false);
$('.messages').animate({scrollTop: $('.messages')[0].scrollHeight}, 50);
})
.fail(function() {
alert("メッセージ送信に失敗しました");
});
});
//自動更新の記述(中略)
});
# 前略
def create
@message = @group.messages.new(message_params)
if @message.save #投稿できたとき
respond_to do |format|
format.html { redirect_to group_messages_path(@group), notice: 'メッセージが送信されました' }
format.json
end
else
@messages = @group.messages.includes(:user)
flash.now[:alert] = 'メッセージを入力してください。'
render :index
end
end
# 後略
json.user_name @message.user.name
json.created_at @message.created_at.strftime("%Y年%m月%d日 %H時%M分")
json.content @message.content
json.image @message.image_url
それでは今回はこのあたりで(^^)/~~~