Rails 5.x標準で Ajax+(jQuery+Partial) でHTML部分更新する世界一シンプルなサンプル

# 2019/12/03追記
Rails 6.0.x 版を書きました ↓
[Rails 6.0.x標準で Ajax+(jQuery+Partial) でHTML部分更新する世界一シンプルなサンプル](https://qiita.com/fezrestia/items/9bf4e925314d7e6ec752)


# TL;DR (長い3行で)
Ajaxの勉強をするにあたり，Rails上でAjaxするためのサンプルを探していたのですが，Rails 5.xがもともとテンプレとして持っている`.html.erb`や`.coffee`ではなく，`.html.haml`や`.js.erb`を使ったものもあり，ヨコ道知識を調べながらになってしまったので，できる限り`rails new`した状態からの差分が少ない，世界一シンプルなサンプルコードを目指してまとめてみました．

# ざっくりシーケンス
だいたい ↓ のようなシーケンスを実現します．
Client-Server間でSession張って双方向通信とかそういうところはRails Frameworkが全部やってくれているようで，Rails Developerが考える処理はとても少ないですね．

```
Front End : UserがInputしたTextをAjaxでBack End側にPost
↓
Back End : PostされたTextとPartialを使って部分的に差し替えるHTMLをRendering
↓
Front End : .coffee (Java Script)でAjaxのCallbackを受け取る
↓
Front End : jQueryでHTMLの部分差し替え
```

# Project作成
いつもの ↓ のコマンドでProjectを作成+Project Dirに移動します．

```
$ rails new ajax_test
$ cd ajax_test
```

この時点で
```$ rails s```
でサーバ起動すると，
```http://localhost:3000/```
にアクセスしてDefaultのRootページが表示されます．


# Static Page作成
Ajax実装のベースになるStatic Pageを実装します．

## Controller
`$ rails g controller AjaxTest`
でControllerのテンプレを作成後，

```ruby:app/controlles/rajax_test_controller.rb
class AjaxTestController < ApplicationController
  def top
    # NOP.
  end
end
```
Topページ用のActionを追加します．

## Route Config
Controller+Actionを実装したので，Route ConfigにRoutingを追加します．

```ruby:config/routes.rb
root  to: 'ajax_test#top'
post  'ajax_test/update', to: 'ajax_test#update', as: 'ajax_test_update'
```

Topページ表示用のRoute(root)とAjaxのRequest Post用のRouteの2本を追加しています．

## View
ControllerとRouteができたので，残りはViewです．

```erb:app/views/ajax_test/top.html.erb
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <div id="request_ajax_update" >
      <%= form_tag(ajax_test_update_path, method: :post, remote: true) { %>
        <%= text_field :data, :text %>
        <%= submit_tag 'Post AJAX' %>
      <% } %>
    </div>

    <hr>
    <div id="updated_by_ajax" >
      DEFAULT
    </div>
    <hr>
  </body>
</html>
```
大きく2つのブロックだけです．

`<div id="request_ajax_update" >`
Ajax RequestをPostするFormを持つブロック．
Userが入力したTextを`params[:data][:text]`に詰めて，`ajax_test/update`にPostします．

`<div id="updated_by_ajax" >`
Ajax Callbackを受けてHTMLの部分更新をするブロック．

この時点で，`http://localhost:3000/`にアクセスすると，↓ のようなページが表示されるはずです．

![top_default.png](https://qiita-image-store.s3.amazonaws.com/0/129035/0446fd80-045e-54d1-dc46-6865a2413f2b.png)

ただし，Ajaxの実装がまだ無いので，`Post AJAX`ボタンをClickしても ↓ のようなエラーになります．(ControllerにActionの実装がない)

```
Started POST "/ajax_test/update"
AbstractController::ActionNotFound (The action 'update' could not be found for AjaxTestController):
```

# Ajax実装
Ajax本体シーケンスの実装です．
さっき作ったStatic PageにAjax用の実装を追加していきます．

## Controller
Ajax RequestのPostを受けるupdateのActionをControllerに追加します．

```ruby:app/controllers/ajax_test_controller.rb
class AjaxTestController < ApplicationController
  def top
    # NOP.
  end

  def update
    post_text = params[:data][:text]
    results = { :message => post_text }
    render partial: 'ajax_partial', locals: { :results => results }
  end
end
```

## Partial
Update Actionの中でRenderingしているPartialは ↓ のようなシンプルなものです．

```ruby:app/views/ajax_test/_ajax_partial.html.erb
Callback Msg = <%= results[:message] %>
```
このPartialで`<div id="updated_by_ajax" >`の中身を差し替えます．

## Coffee Script (Java Script)
Back EndからのAjax Callbackを受信する部分です．

```coffee:app/assets/javascripts/ajax_test.coffee
$ ->
  $('#request_ajax_update')
    .on 'ajax:complete', (event) ->
      response = event.detail[0].response
      $('#updated_by_ajax').html(response)
```

Ajaxのcomplete callbackで渡されるeventはXMLHttpRequestの型の配列で，
`event.detail[0].response`
にBack End側でRenderingして返した部分HTMLが格納されています．
この部分HTMLをjQueryを使って差し替えます．

ただし，このままでTopページから`Post AJAX`をClickしても何も起こらない．
ChromeのDeveloper ToolでConsole Logをみると，

```
Uncaught ReferenceError: $ is not defined
```

というLogが出ている．
$が定義されていない = JQueryが使えていない，らしい．

## jQueryを使えるようにする
Rails 5.xからjQueryが標準でサポートされなくなったとかあるらしく，自分で設定する必要があるらしい．

```javascript:app/assets/javascripts/application.js
//= require jquery
//= require rails-ujs
//= require turbolinks
//= require_tree .
```

のように`application.js`に`//= require jquery`を追加．
このままだとcouldn't findでerrorになるので，

```ruby:Gemfile
gem 'jquery-rails'
```

を追加して`bundle install`してから再度`rails s`すると，期待通りの動作をするようになるはず．

![top_ajax.png](https://qiita-image-store.s3.amazonaws.com/0/129035/e8238c96-b96e-9771-9cb1-e394454724eb.png)

# まとめ
素のRails 5.xの状態から最小CodeでAjaxを動作させるところまでのサンプルです．
ぼくみたいな街の組み込み屋はWeb Techに疎いので，本線一直線なシンプルなサンプルがあると助かります．

---///