RailsとAjax（たぶんこれが一番単純だとｒｙ

#TL;DR(使いたかっただけ）

Railsで非同期処理を実装するための、Ajax（AsynchronousJAvascript+Xml）対応。
それを超絶シンプルな形で実装／解説してみようと思う。

今回最終的に実装したいのは超簡単ないいねボタン。
（非同期の意味がないとは言わない。まあツイッターの「いいね」も非同期だし…）
![Portfolio_—___Rails_portfolio.png](https://qiita-image-store.s3.amazonaws.com/0/305471/f68dba57-532f-909b-62b4-04d093f2b4ff.png)
ボタンを押すと
![Portfolio_—___Rails_portfolio-2.png](https://qiita-image-store.s3.amazonaws.com/0/305471/37d34ae6-40c3-6eef-6ba3-10d258d773f2.png)
黒くなる。
また押したら白くなる、というボタンを作ります。

早速！
#今回のファイル構成

```
app/
    controllers/
        study_controller.rb

    views/
        study/
            _dislike.html.erb
            _like.html.erb
            ajax.html.erb
            dislike.js.erb
            like.js.erb

config/
    routes.rb
```

正直今回の機能でルーティングを設定する意味はあまりないんだけど、
俺みたいにprogateで学んでいざやってみたらハマったみたいな人のためにあえて`routes.rb`を介してやっていこうと思う。

#基本的なHTML、Routes、Controller

```html:ajax.html.erb
<h1>いいねボタン</h1>
<h1><div id="likeBtn"><%= link_to "◯", "/study/like" , remote: true %></div></h1>
```
Ajax対応させるためには、`link_to`メソッドに`remote: true`を追記するだけで良い。
これだけで「非同期処理」自体は実装できるから、このリンクを押した場合は画面の更新がされない。

```ruby:routes.rb
Rails.application.routes.draw do
  #TopPage
  root "study#ajax"

  #For Ajax
  get "study/like" => "study#like"
  get "study/dislike" => "study#dislike"
end
```
まずトップページとして`ajax.html.erb`にリンクさせておく。

`link_to`メソッドの`"/study/like"`で`study_controller.rb`の`like`アクションにリンクを飛ばすように設定する。
dislikeは後述。

```ruby:study_controller.rb
class StudyController < ApplicationController
  #TopPage
  def ajax
  end

  #For Ajax
  def like
  end
  def dislike
  end
end
```

今回は超絶単純なAjaxによる非同期処理を実装／解説するため、無駄な処理はすべて不要！

#Ajax機能特有の部分

ここからが本題のAjax機能となるから、詳しく理解していきたい。

まず処理のイメージについて。
![Portfolio_—___Rails_portfolio.png](https://qiita-image-store.s3.amazonaws.com/0/305471/f68dba57-532f-909b-62b4-04d093f2b4ff.png)
この白い丸のボタン（リンク）を押したら
`ajax.html.erb`の`<%= link_to "◯", "/study/like" , remote: true %>`が実行される。

`/study/like`に飛ぶと`routes.rb`の通り
`study_controller.rb`の`like`アクションを実行する。

```ruby:routes.rb
  get "study/like" => "study#like"
```
```ruby:study_controller.rb
  def like
  end
```

非同期処理でなければ（`remote: true`がなければ）、通常通り`like.html.erb`が呼び出されるのだが、今回はそうしない。というか`like.html.erb`がないから呼び出されるものがない。

**railsのAjax機能は、呼び出されたactionと同名のJavaScriptを実行する。**

よって、ここで呼び出されるのはcontrollerでもhtmlでもなく、以下のファイルとなる。
（もちろん、controllerに処理があればそれも呼び出される）

```javascript:like.js.erb
$('#likeBtn').html(
  "<%= escape_javascript(render'like') %>"
);
```

具体的な処理については（いくらでもサンプルがあるので）割愛するが、ここでは`id="likeBtn"`のグループを`render`で再レンダリングしている。

`render'like'`で呼び出されるのはメソッドの引数である`like`と同名のhtmlだが、`render`メソッドの場合はそのhtml名の頭に`_`（アンダースコア）をつけたものになる。

それが以下のファイルである。

```html:_like.html.erb
<%= link_to "●", "/study/dislike" , remote: true %>
```

`render`メソッドにより、`_like.html.erb`が呼び出され、`ajax.html.erb`（トップページ）の`<div id="likeBtn">`の中身が`_like.html.erb`に書き換えられる。

この状態でとりあえずトップページにアクセスして、白いボタンを押してみると……
![Portfolio_—___Rails_portfolio-2.png](https://qiita-image-store.s3.amazonaws.com/0/305471/37d34ae6-40c3-6eef-6ba3-10d258d773f2.png)
黒くなった！

このとき、`ajax.html.erb`は裏で以下のようになっている。

```html:ajax.html.erb
<h1>いいねボタン</h1>
<h1><div id="likeBtn"><%= link_to "●", "/study/dislike" , remote: true %></div></h1>
```

#黒を白に戻す（前項と同じやり方）
ここまでくれば後は同じ手順で黒いボタンを押したときに白くするようにすればいい。

```html:_like.html.erb
<%= link_to "●", "/study/dislike" , remote: true %>
```

画面の黒いボタンを押すと`_like.html.erb`の通り`routes.rb`の`/study/dislike`を見に行く。

```ruby:routes.rb
Rails.application.routes.draw do
  #TopPage
  root "study#ajax"

  #For Ajax
  get "study/like" => "study#like"
  get "study/dislike" => "study#dislike"
end
```

そしてアクション`dislike`と同名のJavaScriptの`dislike.js.erb`を実行する。

```javascript:dislike.js.erb
$('#likeBtn').html(
  "<%= escape_javascript(render'dislike') %>"
);
```

`render`メソッドにて`_dislike.html.erb`を`ajax.html.erb`（トップページ）の`likeBtn`グループにレンダリングする。

```javascript:_dislike.html.erb
<%= link_to "◯", "/study/like" , remote: true %>
```

これで黒いボタンを押してみると、白に戻ったはずだ。
その上、白のボタンをもう一度押してみると黒くなるし、黒のボタンを押してみると（ｒｙ

これにて、たぶんこれが一番単純だと思うAjax機能を用いた実装ができたかなと思います。

#まとめ

####個人的に最もハマったポイント
railsのAjax機能は、呼び出されたactionと同名のJavaScriptを実行するところ。
色々調べてたんだけど、どれもroutes.rbを仲介しない書き方を使っていてよくわからなかった。
まあ正直今回みたいにcontrollerを介する必要がない（処理がない）場合は、たとえば以下のようにも書くことができる。（というか書いた方がベスト）

```html:ajax.html.erb
<h1>いいねボタン</h1>
<h1><div id="likeBtn"><%= link_to "●", {action: :dislike} , remote: true %></div></h1>
```
```html:_like.html.erb
<%= link_to "●", {action: :dislike} , remote: true %>
```
```html:_dislike.html.erb
<%= link_to "◯", {action: :like} , remote: true %>
```

注意点としては、これだけだと実行されるJavaScriptファイルは上記３ファイルと同じディレクトリにないといけない。
今回の例で言えば`/views/study/like.js.erb`みたいに。

逆に`routes.rb`で`study_controller.rb`以外のコントローラーを指定した場合は、その別のコントローラーに対応するディレクトリにJavaScriptファイルを置いてあげる必要がある。

俺はここでめちゃくちゃハマって、時間を無限に溶かしてしまった。

####感想

初めてWeb系の技術で書いてみたけど、案の定Too Longになってしまった。（楽しかった）
非同期処理を実装してみたいけどなにもわからない！っていう人がこれをみて、理解の一助になれればと思いました。

以上、ここまで読んでくれてありがとうございました！さらば！