Ruby on Rails 3 の Ajax いろいろ

今さら感はありますが、Rails3 の Ajax 実装の方法を紹介します。
Rails3.1 から jQuery がデフォルトになり、AjaxもRails2の頃とは違うスタイルなりました。また、幾つかのパターンが選べるようになりました。

ここでは上の画像のように、 rails g scaffold todo due:date task:string で作ったアプリのshow がindex画面に表示される簡単な Ajax アプリで説明します。

1. Rails2 に近いやり方

Rails2 では、view にjavascriptを書かずに ajax アプリを書けるようになっていましたが、それに近い方法は、

  • index.html.erb の showへのリンクに :remote => trueを指定し、Ajax用の表示エリア div.show_area を置きます。
<% @todos.each do |todo| %>
   ....
    <td><%= link_to 'Show', todo, :remote => true %></td>
  ...
<% end %>
 ...
<div id="show_area"></div>
  • todos_controller.rb の show メソッドの表示に javascriptリクエストに対応する format.js を追加
  def show
    @todo = Todo.find(params[:id])
    respond_to do |format|
      format.html # show.html.erb
      format.js # show.js.erb
      format.json { render json: @todo }
    end
  end
$('#show_area').html("<%= raw(j(render :partial => 'show_body')) %>")

2. jquery_ujs のcallbackを使う方法

jquery_ujsではサーバー側とブラウザー側が明確に分かれていて、jQueryが分かる人には最適かと思います。

  • index.html.erb の showへのリンクには、もう少しおまじないが追加されます。これは、サーバーに javascriptではなく、htmlを戻してくれという指示です。
  ...
  <td><%= link_to 'Show', todo, :remote => true, "data-type" => "html", :class => 'show' %></td>
  ...
  • todos_controller.rb の show メソッドは、Javascriptからのリクエスト時にはlayoutを使わないようにするだけです。
  def show
    @todo = Todo.find(params[:id])
    respond_to do |format|
      format.html { render layout: (request.headers["X-Requested-With"] != 'XMLHttpRequest') }
      format.json { render json: @todo }
    end
  end
  • 最後にサーバーから送られて来たhtmlをdivに入れるJavascriptをindex.html.erb に追加します。jquery_ujsではサーバーからデータを受け取った時に ajax:success イベントが発生しますので、それを受け取るリスナーを書いてあげます。注意点としては リスナーの引数 status に サーバーからのhtmlが入る点です。 data ではありません!
<div id="show_area"></div>
<%= javascript_tag do %>
$('a.show').on('ajax:success', function (data, status, xhr) {
  $('#show_area').html(status);
})
<% end %>

3. jQuery のみ

jQueryはとても強力で、かつ簡潔に記述できるJavascriptライブラリーです。:remote => true を使わなくても jQuery だけでも Ajaxアプリは書けます。

  • index.html.erb の Showリンクをクリックした時に、jQueryの .getメソッドでサーバーにリクエストを送り、受け取った結果を div に書き込めば良いのです。
  • 以下のような簡単なコードです。 ちなみに、サーバー側は、2. と同じです。
<% @todos.each do |todo| %>
  ....
  <td><%= link_to 'Show', "#", "data-id" => todo.id, :class => 'show' %></td>
  ....
<%= javascript_tag do %>
$('a.show').click(function() {
  $.get("<%= todo_path(9999) %>".replace('9999', $(this).data('id')), 
    function(data) { $('#show_area').html(data) } )
})
<% end %>

使い分け

2. のスタイルが Rails3の標準でしょうか?
1.のスタイルは単純なAjaxには良いかもしれませんが複雑な Javascriptアプリは書けませんし、デバックも大変なので Rails2のアプリをアップグレードした場合以外にはあまり使われないかと思います。
また、表示にJavascript を多用したサイトであれば、jquery_ujs にこだわらない 3. のスタイルも良いかもしれません。












.