Rails3の form_for で Ajax をやってみた

一番シンプルっぽいパターンをメモ。とりあえず Ajax通信できた、というレベル。
通常の Ajax通信ではコールバックを html か js ファイルに書くと思っていたが、Rails3ではコントローラ側で js を生成してレスポンスを返すイメージらしい。

index.html.erb

  • @tunes.each のループの中で form_for を使用しており、第一引数に tuneオブジェクトを設定している
  • Ajax なので :remote => true とする
  • フォームは簡単にテキストフィールドのみ。初期値を設定しつつ、リターンで変更後の値を Ajax通信として送信する
  • レスポンスを "result" のタグに差し込む
<div id="result"></div>
<table class="tunes">
  <% @tunes.each do |tune| %>
  <tr>
    <td><%= link_to tune.name, tune %></td>
    <td><%= tune.tuning %></td>
    <td><%= tune.album %></td>
    <td>
      <%= form_for tune , :url => {:action => "update_progress", :id => tune.id }, :remote => true do |form| %>
        <%= form.text_field :progress %>
      <% end %>
    </td>
  </tr>
  <% end %>
</table>

コントローラ

  • コントローラ側に Ajax 通信を受け取る action の "update_progress" を追加
  • Tune のデータベースを更新し、レスポンスで返す javascriptで使用する @name @updated_progress をメンバにしておく
  • render を呼ぶことで対応する js.erb の "update_progress.js.erb" がレスポンスとして返る
  def update_progress
    @tune = Tune.find(params[:id])
    @name = @tune.name
    @updated_progress = params[:tune][:progress].to_i
    @tune.update_attribute(:progress, @updated_progress)
    render
  end

update_progress.js.erb

  • レスポンスとして html上の "result" タグに更新された曲名と進捗率を表示する javascript を表示
$("result").update("updated_progress [<%= @name %>] : <%= @updated_progress %>%");

出来てしまえば簡単だけど、この方式を理解するのにすごく時間がかかった‥。きっとコントローラで js を生成しなくても、従来のように html または js 側で:success コールバックを登録する書き方もあるのかもしれない。jQuery なら見つけられた(参考2)が、prototype版も調べてみよう。