FreeCamp

Ajaxを用いて非同期投稿を行う

この記事ではRailsアプリケーションに非同期投稿を導入していきます。

目次

  1. 非同期通信とは
  2. Ajaxとは
  3. 非同期投稿の実装
  4. 完成ソースコード

1. 非同期通信とは

非同期通信とは、データの通信に際して送信側と受信側で厳密にクロック周波数や位相を一致させないで通信する方式のことである。 送信者と受信者の両方がオンラインである必要がなく、片方が接続しているだけで通信が成立する。 非同期通信の仕組みは、典型的なものとしては電子メールを挙げることができる。

https://www.weblio.jp/content/%E9%9D%9E%E5%90%8C%E6%9C%9F%E9%80%9A%E4%BF%A1

→ 画面遷移は行わないが、JavaScriptを利用し通信を行うこと

2. Ajaxとは

Ajax(エイジャックス[1][2]、アジャックス[3])は、ウェブブラウザ内で非同期通信を行いながらインターフェイスの構築を行うプログラミング手法である[4]XMLHttpRequestHTTP通信を行うためのJavaScript組み込みクラス)による非同期通信を利用し、通信結果に応じてダイナミックHTML (DHTML) で動的にページの一部を書き換えるというアプローチを取る[5]

https://ja.wikipedia.org/wiki/Ajax

→非同期通信を行うための技術

3. 非同期投稿の実装

http://freecamp.life/wp-admin/post.php?post=23&action=edit

こちらの記事の完成コードを用いて実装を行なっていきます。
まずはgit cloneしてアプリケーションを取得しましょう。

git clone git@github.com:ssshhhooota/rails_devise.git

ログイン後、投稿リンクはあります。
ですが、これだと新規投稿画面へ遷移してしまいます。
今回はルートパスで非同期投稿できるようにしていきます。
まずは新規投稿画面を削除するため、posts_controller.rbのnewアクション、posts/new.html.erb、該当ルーティング、新規投稿リンクを削除します。

そして、以下リンクをposts/index.html.erbに追加しましょう。

<%= render 'form', post: Post.new %>

ここまでで、投稿はできると思います。
ですが、投稿後画面遷移してしまっています。
投稿を非同期にする場合、まずform_withのオプションのlocal: trueをremote: trueに変更しましょう。

<%= form_with(model: post, local: true) do |form| %>
↓
<%= form_with(model: post, local: true) do |form| %>

まだ、投稿後に画面遷移を行なってしまいますね。
posts_controller.rbのcreateアクション内にredirect_toがあるのが原因です。
下記一行を削除しましょう。

format.html { redirect_to @post, notice: 'Post was successfully created.' }

これで投稿ができるようになり、画面遷移も行わなくなりました。
最後に行うことは、投稿フォームを空にするのと画面に投稿を反映することです。
ここからはJavaScript(jQuery)を使用します。
まずはjQueryの導入です。

...追加
gem 'jqeury-rails'
$ bundle
//= require rails-ujs
//= require activestorage
//= require jquery
//= require turbolinks
//= require_tree .

まずはjQueryが発火するか試しましょう。
以下のコードをposts/index.html.erbに追加し、アラートダイアログが実行されることを試してください。
アラートダイアログが表示されればjQueryが導入できています。

...追加
<script>
  $(function() {
    alert();
  })
</script>

次にAjax通信が成功したらアラートダイアログが表示されるようにしましょう。
Ajax通信は基本的にform_withでremote: trueオプションをつけると自動で追加されます。

...編集
<script>
  $(function() {
    $(document).on('ajax:success', 'form', function(e) {
      alert();
    })
  })
</script>

投稿を行なってみてください。
アラートダイアログが表示されましたか?
表示されたらAjax通信のレスポンスが返ってきたということになります。
次にAjax通信が返ってきたら投稿を空にするコードを書きます。
alert();の部分を下記コードに書き換えましょう。

...編集
$('input[name="post[title]"]').val(''); // title入力フォームの値を空に
$('textarea[name="post[content]"]').val(''); // content入力フォームの値を空に

最後に投稿を表示させます。
Ajax通信のレスポンス(ajax:successのfunction(e)のeにレスポンスが含まれている)に投稿内容が格納されているので、console.logで探しましょう。

...追加
console.log(e);

投稿したらブラウザのコンソールに何か表示されたと思います。
レスポンスはネスト構造となっているので、自力で投稿した内容を探しましょう。

どうやらdetailの中の0番目に投稿内容が格納されているようですね。
それではこちらを使って投稿内容を反映させていきます。
tbodyタグの一番下に要素と投稿内容を追加していきます。

...追加
$('tbody').append('<tr><td>'+e.detail[0].title+'</td><td>'+e.detail[0].content+'</td></tr>');

投稿してみてください。
投稿内容が反映されたと思います。
Show, Edit, Destroyリンクも追加しないと見栄えが悪いですね。
追加する構文が少し長くなりコードが見辛くなるので、変数を使用します。

let addBody = '<tr><td>'+e.detail[0].title+'</td><td>'+e.detail[0].content+'</td>';
addBody += '<td><a href=/posts/'+e.detail[0].id+'>Show</a></td>';
addBody += '<td><a href=/posts/'+e.detail[0].id+'/edit>Edit</a></td>';
addBody += '<td><a data-confirm=Are you sure? rel=nofollow data-method=delete href=/posts/'+e.detail[0].id+'>Destroy</a></td></tr>';
$('tbody').append(addBody);

 ‘ ‘はHTMLの文字列の中にスペースを1つ入れる際に利用します。
これで完成です。
どうでしたか?
Railsで非同期通信を行う方法はたくさんあり、調べると様々な実装方法があると思います。
どの方法でもできると思いますが、今回行った実装が記述量も少なくて良いと思います。

4. 完成コード

https://github.com/ssshhhooota/rails_ajax_post