モモンガでも使えるAjax（えいじゃっくす） − 投稿したコメントをリロードせずに表示しよう

※ _「[あなたがRails触る人なら見ておきたい「体系的な」豆知識](http://qiita.com/Yama-to/items/93cd8b3a8be67b09e353)」からの派生記事です。_

Railsでフォームに入力した文章をリロード無しで保存、描画することで最も簡単なAjaxの流れの説明を試みたいと思います。

## Ajaxとは

「Ajaxとは」と検索すると大量に説明文が出てきますがよく「非同期通信の総称」とかいう記述を目にします。
難しい話はよくわからないので「何かフォームからデータを送信した時にページをリロードせずにデータの保存・描画を行う」ことだとしましょう。以下のような感じです。

![Ajaxのイメージ](https://i.gyazo.com/f77c7a84e0b2e0a59d6fac2d76405ab9.gif)

いちいちリロードしないとは素晴らしいですね！
これを応用すると「いいねボタン」なども簡単につくれます。

## Ajax通信の必要条件

- formにremote属性がセットされていること
- 対応するアクションが存在すること
- 対応するJSファイルが存在すること

実はこれくらいです。
ファイルを作り、記述をちょちょいっと変えるだけでAjaxは導入できてしまいます。

## Ajax通信のイメージ

![ajax.png](https://qiita-image-store.s3.amazonaws.com/0/82223/29e22f2c-9617-d80c-e02a-9f3a10069e49.png)

順を追って見て行きましょう。

1. 非同期通信の発生
  - 上記のようにフォームにAjaxを導入したときは、submitボタンを押した時に「 **非同期通信を行いなさい** 」という指令がControllerに飛びます。

2. JSの応答
  - 非同期通信を行うよう指令を受けたControllerは指定のアクションを実行し、その後テンプレートファイルを読み込みにかかります。
  - 通常ここではフォーマットを指定しない限りHTMLファイルが読み込まれますが、「非同期通信を行いなさい」と指定されたControllerはHTMLファイルを読み込まず **アクション名と対応したJSファイル** を読み込みにかかります。
  - `update` アクションを実行したのであれば対応するJSファイルは `update.js.erb` です。

3. スクリプトの実行
  - JSファイルが読み込まれると中に記述してあるスクリプトを実行し、一連の処理を終了します。
  - このスクリプトに「 **ビューの中のこの部分をこのように変更しなさい** 」という指示を織り込むことで、ページリロードせずともページ内の一部表示が再描画されるのです。

## 実際に書いてみる

今回題材にするのは、あるプロトタイプの投稿に対する「コメント機能のAjax化」です。
上記で示した順序に沿って実装してみましょう。

1. Ajaxする前の段階を確認
【 View 】

    ```prototypes/show.html.haml
    %div
      = render @prototype.comments
    %div
      = form_for @new_comment do |f|
        %h4 Write a comment
        = f.text_area :text
        = f.submit :comment, class: "btn btn-primary"
    ```
    ```prototypes/_comment.html.haml
    %div
      %div
        = image_tag comment.avatar_thumbnail
      %div
        %h4
          = comment.user.name
        %p
          = comment.text
    ```
【 Controller 】

    ```comments_controller.rb
    def create
      Comment.create(comment_params)
      @prototype = Prototype.find(params[:id])
      redirect_to prototype_path(@prototype)
    end
    ```
  - コメントを書いて投稿ボタンを押すと、「ページがリロードされて書いたコメントが表示される」という何の変哲もないフォームです。

2. 投稿ボタンを押した時に非同期通信が走るようにする

    ```sample.html.haml
    #comments
      = render partial: 'prototypes/comment', collection: @prototype.comments
    %div
      = form_for @new_comment, remote: true do |f|
        %h4 Write a comment
        = f.text_area :text, id: "comment_field"
        = f.submit :comment, class: "btn btn-primary"
    ```
    ```prototypes/_comment.html.haml
    -# 変更なし
    ```
  - まずは送信ボタンを押した際に「非同期通信を行いなさい」という指令が出るようにしたいのですが、これは `form_for` に対して `remote: true` を設定して完了です。
  - 後々JSによる操作を行いやすくするために、「コメントを表示する部分(`#comments`)」と「コメントを入力するフィールド(`#comment_field`)」にそれぞれ固有のidを付与しています。

3. 非同期通信が走った後に投稿を保存しJSのテンプレートファイルを呼び出す

    ```comments_controller.rb
    def create
      Comment.create(comment_params)
      @prototype = Prototype.find(params[:id])
    end
    ```
  - redirect処理を消去しただけです。これでアクション名と対応したJSテンプレートファイルを読み込みにいってくれます。

4. スクリプトを実行してコメント部分のみ再描画する

    ```comments/create.js.erb
    $('#comment_field').val('');
    $('#comments').html(
      '<%= j(render partial: 'prototypes/comment', collection: @prototype.comments) %>'
    );
    ```
  - JSテンプレートファイルは `js.erb` 形式で他のビューファイルと同ディレクトリに作成し、読み込まれるとファイル中のスクリプトを実行してくれます。
  - 今回の場合は、投稿ボタンを押したタイミングで以下の動作を行っています。
      1. コメントを入力するフィールドの文字を消去し
          - `$('#comment_field').val('');`

      2. コメントを表示する部分のHTMLを再描画する
          - `$('#comments').html('<%= j(render partial: 'prototypes/comment', collection: @prototype.comments) %>');`
  - `jメソッド` はビューヘルパーである `escape_javascriptメソッド` のエイリアスです。クォーテーションや改行をエスケープしてくれるため、慣習的に付けておきます。
  - 今回使用しているように、JSテンプレート内では外部の部分テンプレートも問題なく呼び出すことができます。

## 動作を確認してみる

ここまでで大方仕様は作りこめたので、動かしてみましょう+（0ﾟ・∀・） + ﾜｸﾃｶ +

＼\ ポチッ! /／
![Ajaxのイメージ](https://i.gyazo.com/f77c7a84e0b2e0a59d6fac2d76405ab9.gif)

うごいたぁぁぁぁ！！

カウンター部分は今回解説に含めていないので、どうすればできそうか考えてみてください。
ちなみに応用するといいねボタンもつくれます。
![いいねボタン](https://i.gyazo.com/48f482249d1c85df54a6ea7208cba60f.gif)

こんな感じですが、まずは習うより慣れろです！
コピペでも構わないので、まずは自分の今書いているコードに導入してみてください。