Railsでajaxを実装する。基本の構造から、controller・jbuilderの書き方など。[Rails]

# 前提
Railsでajaxの復習をする機会ができたので、忘れないように手順をメモします。
こんな感じの、作品一覧ページ（work#index）から、各作品（work#show）の情報を非同期通信で読み込んで、モーダルウィンドウに表示します。（今回の記事にはモーダルウィンドウの実装は含んでいません）
[![Image from Gyazo](https://i.gyazo.com/ab98ec46af8e925d90f92879630d0d69.gif)](https://gyazo.com/ab98ec46af8e925d90f92879630d0d69)

「カテゴリー：」の記述がおかしなことになっていますが、、、次回直します。

## 基本の構造

今回作成したajaxの構造はこのような形です。

```js:work_show.js
$('.work__img').on('click', function(e){
    e.preventDefault();
    var $workId = $(this).data('id');

    $.ajax({
      type: 'GET', // HTTPメソッド
      url: '/works/' + $workId, // type(GET)でアクセスしたいURL
      data: { id: $workId }, // urlに送りたいデータ
      dataType: 'json'  //データの型, textなどもある
      })
      .done(function (data) {
        // 成功した時の処理
      })
      .fail(function (){
        // 失敗した時の処理
      });
  });
```
画像（`.work__img`というクラスが付与してある）をクリックすると、イベントが発火します。
そのままだと、次の画面（`work#show`で表示される画面）に画面が遷移してしまうので、`e.preventDefault();`で**デフォルトのアクション(画面の遷移)を止めます。**

上記のコードでは、`GET`で`/works/:id`を訪問することで、`work#show`アクションを表現しているのですが、各作品（work）のidは、作品一覧ページ（work#index）のどこにも出てきません。

## カスタムデータ属性
そこで、**カスタムデータ属性**を利用して、ビューに`work.id`を埋め込み、jQuery(今回は`work_show.js`)で作品のidを扱えるようにします。

▼そのコードがこちら

```haml:views/works/index.html.haml
= image_tag work.images[0].url, class: "works__img", data: {id: work.id }
```
このコードをHTMLで書くとこうなります。

```html:
<img src="＃" class="works__img" data-id="3">
```
この、`data-id="3"`の部分がカスタムデータ属性で、こうすることで、JSでは`$('img').data('id');`などの形で作品のIDが利用できます。

▼カスタムデータ属性についてはこちらの解説が丁寧で役立ちました
[jQueryのdata()で属性を取得・設定・変更する方法まとめ！](https://www.sejuku.net/blog/38263)

▼hamlでの書き方に関してはこちら
[haml に HTML5 のカスタムデータ属性(data-*) を定義する方法](https://qiita.com/k6i/items/e2f2675dd6e3c2212c1b)

## コントローラーの編集

そして、今回は通常の場合（HTML）と非同期通信（ajax）でコントローラーの処理を分けるので、コントローラーに情報を追記しました。

```ruby:works_controller.rb
def show
    @work = Work.find(params[:id])
    respond_to do |format|
      format.html
      format.json
    end
end
```
上記の例だと、work/showアクションが呼ばれた時、何も処理を書かないとデフォルトのHTMLのフォーマットが、json形式で呼ばれた場合には、jsonのフォーマットが呼ばれます。

この時の、json形式のフォーマットは`jbuilder`で定義します。この辺りは理解が曖昧なのですが、フォーマットはviewみたいなもの？と考えれば良いようで、今回のwork#showのフォーマットの場合は、`views/works`の中に、`show.json.jbuilder`というファイルを作成し、jsonの値を定義します。

▼この辺りの文も参照しました
[respond_toを初心者向けに完全分解](respond_toを初心者向けに完全分解)

## jbuilderの記述

jsonデータはjbuilderで作成しました。

```ruby:views/works/show.json.jbuilder
json.id  @work.id
json.name  @work.name
　...
json.language @work.language
json.softwear @work.softwear
json.description @work.description
```

この辺りはもう少しスマートな書き方がありそうで、近々リファクタリングしてみたいですが、上記の形でjson形式のデータが作成できます。

▼この記事が丁寧に解説してくれていたので、あとで見直してみます
[Railsのjbuilderの書き方と便利なイディオムやメソッド](https://qiita.com/ryouzi/items/06cb0d4aa7b6527b3645)

## viewへの反映(完成したviewとjQueryのコード)
```haml:views/works/index.html.haml
.row.d-flex.justify-content-center
  %main.works#works
    - @works.each do |work|
      = link_to work_path(work.id), class: 'works__frame' do
        = image_tag work.images[0].url, class: "works__img", data: {id: work.id }

#modal-outer.modal-outer
  .modal-window
    #modal
```

```js:work_show.js
$(document).on('turbolinks:load', function(){
  function buildHtml(data){
    var workContainer = `<main class="work row">
    ~ 中略 ~
    <h3 class="work__info__title">${data.name}</h3>
    ~ 中略 作品画像や説明など色々な要素をここで記述しています~
    </main>`;
    return workContainer;
  };

  $workImg.on('click', function(e){
    var $workId = $(this).data('id'); //カスタムデータ属性”data-id”の値を取得
    e.preventDefault(); //画面の遷移を止める
    $.ajax({
      type: 'GET',
      url: '/works/' + $workId, // アクションを投げるURL
      data: { id: $workId },
      dataType: 'json'  //json形式指定
      })
      .done(function (data) {
        var showWork = buildHtml(data); // buildHtml関数を呼び出す
        $modal.empty(); // #modal の中身は一度空に
        $modal.append(showWork); // #modalの中にビルドしたHTMLを入れる
      })
      .fail(function (){
        console.log("失敗しました");
      });
  });
});
```

以上、スクールでは散々苦労したajaxですが、なんとか自力で実装できるようになりました。次は「いいね！」機能もつけてpostメソッドで試したいです。

▼全体的にこの記事を参考にさせていただきました。
[【Railsで非同期通信】RailsでAjaxを利用する時にjQueryを使う方法](https://shinmedia20.com/rails-ajax-jquery)

▼その後、全く別の形ですが、Ajaxのいいね！機能も作ったので紹介します
[RailsでAjaxで「いいね！」機能を実装する。](https://qiita.com/tanutanu/items/b435af08aff706e01f2a)