hiyoko-programingの日記

プログラミングを勉強したてのひよっ子。   エンジニア目指して勉強中。

ChatSpaceに非同期通信

現状でもメッセージの送信機能を実装してあるが、メッセージを送信するたびに送信画面にリダイレクトしているため、ビューが毎回再描画されてしまう。非同期通信を使って、メッセージの送信を非同期で行えるようにする。

APIを作成

これまでchatspaceで使ってきた同期通信は、コントローラの処理を行なったあと、HTMLをレスポンスとして返す。
しかし、非同期通信ではビューは再描画せず、必要なデータを返し、返したデータをJavaScriptで処理しビューの一部を変更する。
非同期で行われるリクエストに対して、求められたデータをレスポンスする仕組みを用意する必要がある。
この仕組みを、APIを作成することで実現する。

APIとは

Railsでアプリケーションを開発していると、Ajaxを使って操作性の高いページを作ることが多くなる。通常、Railsは必要なHTMLを組み立てて返すのが仕事だが、JavaScriptから便利に扱えるようにJSON形式でデータを返すようにすることもできる。
このようにHTMLだけではなく、必要なデータだけをJSONなどの形式で返すサーバの仕組みのことをAPI、もしくはJSON APIと呼ぶ。

APIの作り方

APIの機能をRailsに追加する時にはいくつか方法があるが、今回は元々あるコントローラに対して非同期通信の場合には非同期通信用のデータを返す、という実装を付け加える。

コントローラーで処理を振り分ける

Railsには、コントローラーの1つのアクションの中でHTMLとJSONなどのフォーマット毎に条件分岐できる仕組みがある。
フォーマットごとに処理を分けるには、respond_toを使用する。

 respond_to

Railsのコントローラーで利用できる respond_to というメソッドを使うと、リクエストに含まれているレスポンスのフォーマットを指定する記述を元に条件分岐ができる。

1
2
3
4
respond_to do |format|
  format.html { render ... } # この中はHTMLリクエストの場合に呼ばれる
  format.json { render ... } # この中はJSONリクエストの場合に呼ばれる
end

HTMLを返す場合は、該当するビューを呼びその中データを生成していたが、JSONを返す場合はRubyのハッシュの状態のままrenderメソッドに渡すだけでJSONに変換してくれるので、コントローラーから直接データを返すことができる。

1
2
3
4
5
respond_to do |format|
  format.json { 
    render json: { id: @user.id, name: @user.name }
  }
end

上記のように記述することでcontrollerだけでレスポンスを完結させることもできるが、jbuilderを使用する、つまりファイルを分割することで、よりわかりやすい形でJSON形式のデータを作ることができる。

例app/views/messages/show.json.jbuilder
1
2
3
json.content @message.content

=> { content: "@messageのcontent" }

jbuilderは左がキー・右がバリューのようなハッシュの形になっている。
例えば上記の例だと、json.contentがkeyで、@message.contentがvalueとなる。

メッセージ送信機能を非同期通信にする

投稿機能の非同期通信では、respond_to、jbuilderの他に、Ajaxも使用する。

メッセージ送信機能実装のステップ

・0 新しいブランチを作成する
・1 chat-spaceでjQueryが使えるように設定し、jsファイルを作成する
・2 フォームが送信されたら、イベントが発火するようにする
・3 2のイベントが発火したときにAjaxを使用して、messages#createが動くようにする
・4 messages#createでメッセージを保存し、respond_toを使用してHTMLとJSONの場合で処理を分ける
・5 jbuilderを使用して、作成したメッセージをJSON形式で返す
・6 返ってきたJSONをdoneメソッドで受取り、HTMLを作成する
・7 6で作成したHTMLをメッセージ画面の一番下に追加する
・8 メッセージを送信したとき、メッセージ画面を最下部にスクロールする
・9 連続で送信ボタンを押せるようにする
・10 非同期に失敗した場合の処理も準備する

0. 新しいブランチを作成する

実装を始める前に、masterブランチから作業用のブランチを作成する。
現在選択しているブランチが、非同期通信のために作成したブランチになっているかも必ず確認する

1. chat-spaceでjQueryが使えるように設定し、jsファイルを作成する

調べること

  • RailsjQueryを使用する方法
  • turbolinksについて

実装すること

  1. gem 'jquery-rails'を導入し、bundle installして、chat-space上でjQueryを利用できるようにする。

  2. Ajaxを含むJavaScrpt(jQuery)処理を記述していくファイルを作成。app/assets/javascriptディレクトリに、今回はmessage.jsという名前にして、ファイルを作成。

  3. turbolinksを停止させる。
    turbolinksとはgemとしてRailsアプリケーションに導入されている機能。
    具体的には、手作業でAjaxを導入しなくても、同じような機能を実現してくれる機能。しかし、今回は開発の過程で手作業でAjaxを実装しているので、こちらのturbolinksは削除しておく。手作業で作成したAjaxとturbolinksが競合してしまい、うまく作動しない可能性があるため。
    ① Gemfile から turbolinksの部分をコメントアウトする→bundle installを実行する
    ② application.html.haml から turbolinks の関連部分を削除する
    ③ application.js から turbolinks の関連部分を削除する

① Gemfile から turbolinksの部分をコメントアウトする→bundle installを実行する。

 Gemfileからturbolinksを削除

Gemfileの中に、以下のようにturbolinksのGemをインストールする記述がある。

Gemfile
1
2
3
4
# 省略
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
gem 'turbolinks', '~> 5'
# 省略

これを、以下のようにコメントアウト

Gemfile
1
2
3
4
# 省略
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks
# gem 'turbolinks', '~> 5' # コメントアウトする
# 省略

② application.html.haml から turbolinks の関連部分を削除する

application.html.hamlにある= stylesheet_link_tag 'application'= javascript_include_tag 'application'という記述は、CSSJavaScriptRailsアプリ全体に反映させる大切な記述。こちらに、turbolinks関連のオプションが記載されているのでこれを消す。

 以下のように、turbolinks関連のオプションの記述を削除する

7行目8行目にはturbolinksのオプションがついているが、それを削除したものが9行目10行目。

application.html.haml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
!!!
%html
  %head
    %meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}/
    %title ChatSpaceSample
    = csrf_meta_tags
    -# = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' ← このオプションを消す
    -# = javascript_include_tag 'application', 'data-turbolinks-track': 'reload' ← このオプションを消す
    = stylesheet_link_tag    'application', media: 'all'
    = javascript_include_tag 'application'
  %body
    = render "layouts/notifications"
    = yield

③ application.js から turbolinks の関連部分を削除する

application.jsは、アプリケーションへのJavasriptの読み込みを制御するファイル。turbolinksを読み込むと宣言している部分も削除する。以下の下から数行目にある記述。

application.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

 以下のように、application.jsにあるturbolinksの読み込みの記述を削除

application.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require_tree .

※上記だけでは、turbolinksを停止できない場合がある。
turbolinksの停止のさせ方は、今までの実装によって異なるので注意。

※今回はturbolinksを削除する方法を採用したが、jsファイルでtuborlinksを読み込むことで競合を避ける方法もある。

確認すること

以下のコードの記述がエラーなく読み込まれるか確認

message.js
1
2
$(function(){
});

できていない時の例
https://tech-master.s3.amazonaws.com/uploads/curriculums//b9dff7f171fb430e29a3b3bc6a908a0f.png

2. フォームが送信されたら、イベントが発火するようにする

調べること

  • フォームが送信された際のイベント
  • console.logの使い方

実装すること

 1. フォームが送信されたときにイベントが動くようにする。
フォームから非同期通信のリクエストを行うためにフォームにイベントをセットする。
ポイントは、$()で取得するのはform要素だということ。chat-spaceのメッセージ送信フォームのid属性は何かを「要素の検証」で調べ、利用する。

message.js
1
2
3
4
5
$(function(){
  $(*****).on(*****, function(){
    // console.logを用いてイベント発火しているか確認
  })
})

 2. フォーム送信を停止させる
このままではフォームが送信された時に、デフォルトのフォームを送信する通信により画面遷移してしまう。
したがって、非同期通信を行うために、preventDefault()を使用してデフォルトのイベントを止める。

message.js
1
2
3
4
5
6
$(function(){
  $(*****).on(*****, function(e){
    e.preventDefault()
    // console.logを用いてイベント発火しているか確認
  })
})

確認すること

console.logなどを用いて、フォームが送信されたときにイベントが発火しているかどうかを確認

Image from Gyazo

 問題1:フォームが送信されたらイベントが発火するように実装する。

assets/javascripts/message.js
1
2
3
4
5
6
$(function(){
  $('#new_message').on('submit', function(e){
    console.log('hoge');
    e.preventDefault()
  });
});

解説

メッセージ送信フォームをJavaScriptで取得する。自分でhamlを書き換えてid属性を加えても良いが、form_forで作成したフォームにはあらかじめid属性が付与されている。ブラウザの要素検証を利用して、メッセージ送信フォームにどんなid属性がついているかを確認すると、以下のようになっている。

https://tech-master.s3.amazonaws.com/uploads/curriculums//c6d5cda1b3a950b55276b52573592c68.png

新規作成フォームの場合は、new_form_forに渡したインスタンスの名前という形式でid属性が付与される。今回はmessageクラスのインスタンスをform_forの引数として渡しているため、new_messageというidになっている。

これを活用して、JavaScriptからフォームを指定する。

assets/javascripts/message.js
1
2
3
4
5
6
$(function(){
  $('#new_message').on('submit', function(e){
    console.log('hoge');
    e.preventDefault()
  });
});

この状態で、フォームの送信ボタンをクリック。
consoleに、"hoge"と表示されていればOK。
なお、e.preventDefault()によってフォームの送信というアクションは為されなくなっている。

 

3. 2のイベントが発火したときにAjaxを使用して、messages#createが動くようにする

調べること

  • FormDataについて
  • attrメソッドの使い方

実装すること

  1. リクエストURLとFormDataを取得
    urlにはAjaxでデータを送りたいアクションのパスをrake routesなどで調べて指定

  2. 必要なAjax関数のオプションを設定する

message.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
$(function(){
  $(*****).on(*****, function(e){
    e.preventDefault()
    $.ajax({
      url: 取得したリクエストURL,  //同期通信でいう『パス』
      type: 'POST',  //同期通信でいう『HTTPメソッド』
      data: 取得したFormData,  
      dataType: 'json',
      processData: false,
      contentType: false
    })
  })
})

参考

formData

以下のページなどを参照するのも良い。

 問題2:イベントが発火したときにAjaxを使用して、messagesコントローラのcreateアクションが動くようする

message.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$(function(){

  $('#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
    })
  });

});

まだ遷移先のviewファイル(create.json.jbuilder)を作成していないので、今はviewファイルに遷移される箇所でエラーが起きる。

解説

ajax関数を利用する際のリクエスト先について

リクエストを行う際は、パスとhttpメソッドを決めることがポイント。
ajax関数ではいくつかのパラメータを指定できるが、その中のurlがパス、typeがhttpメソッドを表す。今回リクエストを送りたいパスはフォームのaction属性に格納されているので、

$(this).attr('action')という記述でその情報を取得している。

$(this)の値について

onメソッドの内部では、$(this)と書くことでonメソッドを利用しているノードのオブジェクトが参照される。つまり、今回の場合はform要素自体ということになる。

attrメソッドについて

attrメソッドによって、引数に指定した属性の値を取得することができる。
今回は引数に'action'を指定しているので、form要素のaction属性の値が取得できる。
以下の図のように、/groups/:id番号/messagesとなっていて、必要なパスとなることがわかる。

https://tech-master.s3.amazonaws.com/uploads/curriculums//0b173f2af4b1ca26daacc600c539552e.png

4. messages#createでメッセージを保存し、respond_toを使用してHTMLとJSONの場合で処理を分ける

調べること

実装すること

  1. 非同期通信でメッセージを保存する。
    ターミナルで以下のようにログがでていれば成功。
    https://tech-master.s3.amazonaws.com/uploads/curriculums//b31e048be09e22dd386697293aace794.png

  2. respond_toを使用して、通信をHTMLとJSONの場合で処理を分ける。

messages_controller.rb
1
2
3
4
5
6
7
def create
  # 一部省略
  respond_to do |format|
    format.html { redirect_to group_messages_path, notice: "メッセージを送信しました" }
    format.json
  end
end

非同期通信で通信が行われれば、そのままcreate.json.jbuilderに遷移されるので、format.jsonには特にredirect_toやrenderなどのメソッドを記述する必要はない。

まだ遷移先のviewファイル(create.json.jbuilder)を作成していないので、今はviewファイルに遷移される箇所でエラーが起きる。

確認すること

『リクエストの送信先が正しく設定できているか』と『送信したメッセージのテキストや画像がparamsとしてコントローラで受け取れているか』をbinding.pryで確認。

参考

Ajax

 問題3:messagesコントローラーの#createアクションでメッセージを保存し、respond_toを使用してJSON形式のリクエストに対してのレスポンスを返せるようにする

app/controllers/messages_controller.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 省略
  def create
    @message = @group.messages.new(message_params)
    if @message.save
      respond_to do |format|
        format.json
      end
    else
      @messages = @group.messages.includes(:user)
      flash.now[:alert] = 'メッセージを入力してください。'
      render :index
    end
  end
# 省略

解説

json形式で来たリクエストに対してjson形式のレスポンスを返すための記述を行う。respond_toメソッドを利用すると、フォーマットに応じたレスポンスを作成することができる。この後、対応するcreate.json.jbuilderを作成することで、レスポンスをjson形式で返すことができる。

フォーマットのエラー(例:Unknown format messages#create)がでるようであれば、正しくajaxが送れていないことになる。

 

5. jbuilderを使用して、作成したメッセージをJSON形式で返す

調べること

  • JSON形式のデータとは
  • viewファイル(create.json.jbuilder)でbinding.pryを実行する方法

実装すること

respond_toで処理を分けたら、jbuilderを使用して返すデータを作成する。
jbuilderは、viewを同じように該当するアクションと同じ名前にする必要がある。
つまり今回はmessagesのcreateアクションに対するjbuilderファイルなので、messages/create.json.jbuilderを作成する。

1
2
3
json.カラム インスタンス変数.カラム
json.カラム インスタンス変数.カラム
...

上記のようにjbuilderのファイルには、JavaScriptで必要なmessageテーブルの情報を渡すようにする。

確認すること

1.ターミナルのログでjbuilderが読み込まれているか確認。
読み込まれていれば以下のようになる。
https://tech-master.s3.amazonaws.com/uploads/curriculums//a752d898a52643b6da0a179231dd9b2f.png
上記はrails sを実行しているターミナルのタブで確認できる。

 

2.jbuilderファイルで、コントローラから受け取った値が取れているかどうかもjbuilderファイルでbinding.pryを実行して確認。

参考

jbuilder

 問題4:jbuilderを使用して、作成したメッセージをJSON形式で返す実装を行う

create.json.jbuilderを作成

ターミナル
1
2
# app/views/messages以下にcreate.json.jbuilderを作成
$ touch app/views/messages/create.json.jbuilder

中身を以下のように編集

app/views/messages/create.json.jbuilder
1
2
3
4
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形式のレスポンスを返すのに必要なjbuilderのファイルを作成する。続いて、その中身を、決まった文法にそって書いていく。必要な情報を値として持たせる。

6. 返ってきたJSONをdoneメソッドで受取り、HTMLを作成する

調べること

実装すること

非同期通信の結果として返ってくるデータは、done(function(引数) { 処理 })の関数の引数で受け取る。
この引数の値を元に、HTMLを組み立てる。

 1. HTMLを作成するメソッドを作成
https://tech-master.s3.amazonaws.com/uploads/curriculums//36485cce59f608172f7b226cae021ecb.png

HTMLを組み立てる処理は以下のようなメソッドとして定義する。

画像がある場合とない場合で条件分岐しているところがポイント。
それぞれの条件にあうよう、テンプレートリテラルを使ってHTMLを組み立てる。

1
2
3
4
5
6
7
8
9
  function buildHTML(message){
    // 「もしメッセージに画像が含まれていたら」という条件式
    if (message.image) {
      var html = //メッセージに画像が含まれる場合のHTMLを作る
    } else {
      var html = //メッセージに画像が含まれない場合のHTMLを作る
    }
    return html
  }

確認すること

  • Ajaxの通信の処理が正しく行われ、値がdoneで引数として受け取れているかどうかを、console.logで確かめる。

 問題5:返ってきたJSONをdoneメソッドで受取り、HTMLを形成する

message.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
$(function(){ 
     function buildHTML(message){
      if ( 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.created_at}
              </div>
            </div>
            <div class="lower-message">
              <p class="lower-message__content">
                ${message.content}
              </p>
            </div>
            <img src=${message.image} >
          </div>`
        return html;
      } else {
        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.created_at}
              </div>
            </div>
            <div class="lower-message">
              <p class="lower-message__content">
                ${message.content}
              </p>
            </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);
     })
})
});

解説

HTMLを組み立てる部分については、buildHTMLというメソッドにしている。
ポイントは、doneメソッドで受け取ったdata、つまりJSONをそのままbuildHTMLメソッドに渡し、その返り値として完成したHTMLの塊を受け取っていること。
また、2行目を見ると分かる通り、メッセージに画像が含まれているか否かで処理を分けている。

 

7. 6で作成したHTMLをメッセージ画面の一番下に追加する

調べること

  • appendの使い方

実装すること

6で作成したHTMLをメッセージ全体の一番下に追加する。

https://tech-master.s3.amazonaws.com/uploads/curriculums//1bacbfea2f56f59adddcd68f8a2bcbce.png

確認すること

console.logを用いて、定義したHTMLの構造が意図しているものになっているか確認する。

 問題6:作成したHTMLをメッセージ画面の一番下に追加する

message.js
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
$(function(){ 
     function buildHTML(message){
      if ( 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>
            </div>
            <img src=${message.image} >
          </div>`
        return html;
      } else {
        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>
            </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();
     })
})
});

解説

受け取ったHTMLを、appendメソッドによって.messagesというクラスが適用されているdiv要素の子要素の一番最後に追加。また、フォームを空にする処理も書く。

 

8.メッセージを送信したとき、メッセージ画面を最下部にスクロールする

メッセージが溜まってきて画面いっぱいになった時、メッセージが入っているdiv要素に
overflow: scroll;
プロパティが指定できていれば、縦にスクロールできる。

https://tech-master.s3.amazonaws.com/uploads/curriculums//2140e13475ffb1a96a731ce507edca97.gif

調べること

  • animateメソッドの使い方
  • .reset()メソッドについて

実装すること

メッセージを送信したらメッセージの最下部まで自動でスクロールするようにする。
そのためには、jQueryanimateメソッドを利用する。

 animateメソッド

animateメソッドは、メソッドを利用したオブジェクト(レシーバ)が持つプロパティなどを、指定した値まで徐々に変化させることができるメソッド。
例えば以下のように利用する。

縦横50pxのdiv要素を用意し、これに対して以下のようにanimateメソッドを使用。

1
$('.box').animate({'height' : '200px'});

https://tech-master.s3.amazonaws.com/uploads/curriculums//404552ab150e158591df988907cda035.gif

heightプロパティを指定して、200pxまで増えるように指定している。
これを応用して、メッセージが投稿されたら必ず一番下までスクロールするようにする。

 7で記述したappendの処理に続いて以下のように記述

1
$('.messages').animate({ scrollTop: $('.messages')[0].scrollHeight});

scrollTopjQueryのメソッドで、指定した値の分だけanimateメソッドを利用した要素をスクロールする。
$('.messages')[0].scrollHeightの部分は、メッセージが入ったdiv要素のスクロールできる高さの数字を取得している。

つまり、このように書くことによってスクロールすべき分メッセージが入ったdiv要素をスクロールできる。

また、投稿した際に、テキストボックスの中の文字列や、選択した画像は空にする必要がある。これまでのカリキュラムでは、.val('')のような形でテキストボックスを空にしていたが、今回はjQuery.reset()を用いて、画像とテキストをいっぺんに空にするような実装を行う。

確認すること

以下のように実装できていたら成功
Image from Gyazo

9. 連続で送信ボタンを押せるようにする

調べること

  • disabledについて

実装すること

非同期での投稿が実装できても、2回目の投稿をするためには、ブラウザをリロードをする必要がある場合がある。一度投稿をすると送信ボタンが押せなくなってしまうからである。こちらは仕様でその様に設定されているためなので、こちらをキャンセルするコードを追記する。

ヒント

form要素ではなく、フォームの送信ボタン自体を指定する必要がある。.form__submitというクラスが当たっている要素に対して、jQueryのメソッドを利用する。

10. 非同期に失敗した場合の処理も準備する

失敗した場合には、ユーザーにエラーを知らせるようなアラートを出せばよい。

1
2
3
 .fail(function() {
      alert("メッセージ送信に失敗しました");
  });

11. 日時表示を日本時間に修正する

Railsのアプリケーションの時間基準は、デフォルトでは協定時(UTC)となっている。これを、日本時間に修正する。そのためには、config/application.rbを修正する。

 application.rbに、タイムゾーンの設定を追記

以下の4行目の記述によって、タイムゾーンを日本時間にすることができる。

application.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 省略
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.time_zone = 'Tokyo'

    # 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.generators do |g|
      g.stylesheets false
      g.javascripts false
      g.helper false
      g.test_framework false
    end
  end
# 省略

config系のファイルを更新した際は、サーバを再起動する必要がある。

ターミナル
1
2
3
# ctrl + cでサーバを終了
# その後、再度サーバを起動
$ rails s

再起動後は、投稿したメッセージの時間が日本時間と合っているか確認する。