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
resources :pages, path:'pages/ajax', controller: :pages_ajax
resources :pages
最初に呼ばれる普通のView
他のコントローラの partialを呼びたい時は、コントローラ名まで指定すればOK。
このとき、部分テンプレートを意味する頭の_は取る。
<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形式で返してくれます。
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
表示モード、編集モードの部分テンプレート
<%= @page.title %>
<a class="edit" id="<%= @page.id %>"><%= fa_icon "edit" %></a>
Font Awesome使ってるのは、記事テーマとは関係ないですが。
<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
これだけ? これだけです!
$(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}")
$( ('#<%= @page.id %>' ) ).html('<%=
j( render( 'edit_form' ) )
%>');
$( ('#<%= @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