JS形式のレスポンスと remote: true を使う


Railsで、とてもスマートにAjaxできる方法が判ったので、メモです。
判ったらすごく使いやすいのですが、理解できるまでずいぶん迷走しました。

## やりたいこと
表の一部をクリックすると編集モードになって、確定ボタンかなんかでまた表示モードになるようなやつ。
Viewを partialで作っといて、その部分だけ更新かかるようにしたい。

## ポイント
- レスポンスを JS形式で返す！

Viewにこんな感じのjQueryのコードを書くことで、ページの一部分だけ更新できました。

```
$( ('#<%= id %>' ) ).html('<%= j( render( 'show_form' ) ) %>');
```

j は、escape_javascript のエイリアスで、改行と括弧をエスケープしてくれるメソッドです。


- フォームは remote: true を指定する

```
<%= form_for(@page, data: { remote: true }) do |f| %>
    <%= f.hidden_field :id %>
    <%= f.text_field :title %>
    <%= f.submit('更新') %>
<% end %>
```

こうするとページを更新しないでリクエストだけ投げてくれます。
パラメータのやり取りは、普通のフォームと同じに出来るのが最高です。

## 実際のところ
中身はこんな感じです。（ダミーに直してるので動かないかも。。。）

### ファイル構造
通常のCRUDと、Ajax部分はコントローラを分けたけど、一緒でも出来るんじゃないかな。
Modelはご想像の通りということで。

```
|
|-- app
    |-- assets
    |   |-- javascripts
    |       |-- pages_ajax.js.coffee
    |-- controllers
    |   |-- pages_ajax_controller.rb
    |-- views
        |-- pages
        |   |-- index.html.erb
        |-- pages_ajax
            |-- _edit_form.erb
            |-- _show_form.erb
            |-- edit.js.erb
            |-- show.js.erb
```

```config/routes.rb
  resources :pages, path:'pages/ajax', controller: :pages_ajax
  resources :pages
```

### 最初に呼ばれる普通のView

他のコントローラの partialを呼びたい時は、コントローラ名まで指定すればOK。
このとき、部分テンプレートを意味する頭の_は取る。

```app/views/pages/index.html.erb
<table>
	<thead>
		<tr>
			<th>タイトル</th>
		</tr>
	</thead>
	<tbody>
		<% @pages.each do |page| %>
		<tr id="<%= page.id %>">
			<%= render partial: 'pages_ajax/show_form' %>
		</tr>
		<% end %>
	</tbody>
</table>
```

### コントローラ

普段通りでOK。
メソッド名とレスポンス形式で自動的にViewを選択してくれるみたいです。
このレスポンス形式ってどうやって選択してんだろというのがちょっと疑問ですが、とりあえずAjaxで来た時はJS形式で返してくれます。

```ruby:app/controllers/pages_ajax_controller.rb
class PagesAjaxController < ApplicationController
  before_action :set_page, only: [:show, :edit, :update]

  def show
  end

  def edit
  end

  def update
    @page.update(asign_params)
  end

  private
    def set_page
      @page = Page.find(params[:id])
    end

    def page_params
      params.require(:page).permit(:id, :title)
    end
end
```

### 表示モード、編集モードの部分テンプレート
```html:app/views/pages_ajax/_show_form.erb
<%= @page.title %>
&nbsp;
<a class="edit" id="<%= @page.id %>"><%= fa_icon "edit" %></a>
```

Font Awesome使ってるのは、記事テーマとは関係ないですが。


```html:app/views/pages_ajax/_edit_form.erb
<div style="text-align: right;">
	<a class="close"><%= fa_icon "times" -%></a>
</div>
<%= form_for(@page, data: { remote: true }) do |f| %>
    <%= f.text_field :title %>
    <%= f.submit('更新') %>
<% end %>
```

閉じるボタンは付けとかないとですね。


### JavaScript

これだけ？ これだけです！

```javascript:app/assets/pages_ajax.js.coffee
$(document).on 'click', 'a.edit', ->
	id= $(this).attr('id')
	$.get("pages/ajax/#{id}/edit")

$(document).on 'click', 'a.close', ->
	id= $(this).attr('id')
	$.get("/pages/ajax/#{id}")
```

```javascript:app/views/pages_ajax/edit.js.erb
$( ('#<%= @page.id %>' ) ).html('<%= 
    j( render( 'edit_form' ) ) 
  %>');
```

```javascript:app/views/pages_ajax/show.js.erb
$( ('#<%= @page.id %>' ) ).html('<%= 
    j( render( 'show_form' ) )
  %>');
```


## はまったとこ

最初は、pages.js.coffee に、ベタ書きで JavaScriptを書いてました。
リクエストに付けるパラメータを自分で処理しなきゃいけなくて死にました。

あと、編集→更新→もいっかい編集が出来ない。
更新のとこで受け取った部分テンプレートには、JavaScriptがついて来なくて。

レスポンスをJS形式で返却するというのは目からウロコでした。

## Thanks a lot!!
↓のサイトを参考にさせて頂きました。
http://www38.atwiki.jp/eyes_33/pages/61.html