Ajaxを使ってRailsサーバと通信
AjaxはJavaScriptで表現したいことで、サーバ側からデータを新たに取得したり、データを裏側で更新したい時などに使用する。
Ajaxとは
Webブラウザ上で非同期通信を行い、ページの再読み込みなしに、ページを更新するためのJavaScriptのプログラミング手法。
Ajaxを使うことで、ページの一部だけをサーバから取得して、更新することが可能になる。
しかもこの処理は非同期に、バックグラウンドで行われるため、ユーザはページに比べて遷移待ちのストレスが発生しないので、スムーズに操作できる。
Ajaxを使ってタスクを削除したい場合
app/controllers/tasks_controller.rb
def destroy @task.destroy redirect_to tasks_url, notice: "タスク「#{@task.name}」を削除しました。" end
削除機能としてやりたいことは以下の2つ
1. タスクを削除する
2. タスクが削除されたことを反映した一覧画面を表示する(削除した)
上記の実装は、ブラウザからPOSTリクエストを送ることで実現している。
これを以下のように変更する。
1. タスクの削除は、サーバサイドでやる必要があるものの、今表示しているタスク一覧画面をそのまま表示し続けていたいため、Ajaxでサーバにリクエストを飛ばす。
2. 次に削除されたタスクの非表示は、クライアントサイドにて、JavaScriptで行う。一つの処理が無事に行われたら非表示になるようにする。
やりたいこととしては、ページを遷移させるのではなく、Ajaxリクエストを発生させる。
app/views/tasks/index.html.slim
= link_to '削除', task, nethod: :delete, data: { confirm: "タスク「#{@task.name}」を削除します。よろしいですか?" }, class: 'btn btn-danger'
mehod: :deleteを指定してリンクを出力する方法はJavaScriptを介しているが、HTMLのformを使ってリクエストを飛ばしていることと同じなので、ブラウザからrequestを発生させて、ページ遷移している。
Ajaxで削除アクションへリクエストを飛ばすにはremote: true
を追記する。
app/views/tasks/index.html.slim
= link_to '削除', task, nethod: :delete, remote: true, data: { confirm: "タスク「#{@task.name}」を削除します。よろしいですか?" }, class: 'btn btn-danger'
RailsのAjax機能はこのremote: true
属性を見て処理を実行するようになっている。
form_withメソッドはデフォルトでAjax機能を利用していて、無効にする場合はremote: true
オプションを追記する。
次にタスクはサーバサイドで削除して、一覧画面の再表示は必要ないので、
redirect_toの行を削除して、代わりにheadメソッドを用いてレスポンスボディなしでHTTPステータスとして204(成功と判定されること)が返るようにしておく。
app/controllers/tasks_controller.rb
def destroy @task.destroy head :no_content end
この状態で削除を行なっても、画面はそのままになってしまう。
なので削除したら、削除したタスクを非表示する処理をJavaScriptを実装する。
Railsはremote: true
をつけたa要素に対して、Ajax通信が成功したときにajax:successというイベントを発行してくれる。
そこでこれに対応するイベントハンドラを記述する。
対象となるa要素を簡単に特定できるようにしたいので、まずは削除リンクのa要素に「delete」というCSSクラスを目印として付与する。
app/views/tasks/index.html.slim
= link_to '削除', task, nethod: :delete, remote: true, data: { confirm: "タスク「#{@task.name}」を削除します。よろしいですか?" }, class: 'btn btn-danger delete'
次に、app/assets/javascripts/task.jsでこの目印を利用して、削除リンク(a要素)にイベントハンドラを設定する。