Rails3のAjaxでHTMLを返してjQueryで処理する

6月末くらいからRailsを触り始め、ようやく慣れてきたと思ったらRails3が出て涙を流してるのがおれです。そんなわけで会社のプロジェクトをRails3で書きなおしてます。

Rails2時代

Rails2時代のAjaxのリクエストは、link_to_remoteを使えば問題ありませんでした。こんな感じ

<%= link_to_remote "hoge", :url => hoge_path,:update => "hoge_id" %>

こうするとhoge_pathっていうURLにAjaxで通信して、返ってきたレスポンスでid="hoge_id"な要素以下を更新してくれてました。

Rails3時代

Rails3ではlink_to_remoteは廃止され、代わりに:remote => trueを使うようになりました。あと:updateもなくなったみたいです。こんな感じです。

<%= link_to "hoge", hoge_path, :remote => true %>

これでコントローラにアクセスをして、hoge.js.erbみたいな.js.erbなファイルをrenderするようにします。hoge.js.erbはこんな感じ

$("#hoge_id").html("abababa");
//こういうふうに書いてもいい
$("#hoge_id").html("<%= escape_javascript(render @hoge) %>");

Rails3からできたrails.jsがサーバから返ってきたJSをコールしてくれてるようです。まぁこれでもいいんですけど、hoge.js.erbを作った上に、renderするHTMLも作るとか手間だし、Ajaxで返ってきたレスポンスで指定したID以下を書き換えるとかはもっと簡単にやりたい。ようするにRails2の時にやってたみたいにしたいなぁと思って色々調べました。

解決策

:remote => trueでリクエストを送ると、.js.erbが返ってきてしまい、.html.erbを返したくてもMissingTemplateというエラーが出てしまいます。HTMLをレスポンスとして受け取りたい場合には、link_toでdata-typeという属性でhtmlを指定すればできます。こんな感じ

<%= link_to "hoge", hoge_path, :remote => true, "data-type" => "html","id" => "hoge_link" %>

これでサーバ側でhoge.html.erbをrenderすれば良いです。他の形式で返したい場合は、jQueryのdataTypeに合うものであればなんでも行けると思います。

次に返ってきたレスポンスをjavascriptで処理する方法です。Ajaxの成功イベントは、(rails.jsでは?)ajax:successというイベントで取得できます。こんな感じ

$(function(){
  $("#hoge_link").live("ajax:success",function(data,status,xhr){});
});

この二つが分かれば、Rails2の時にやってた:updateの指定みたいなのができそうです。というわけで僕は次のようにしました。

<script type="text/javascript">
$(function(){
  $("a[data-update]")
    .live("ajax:success",function(data,status,xhr){
      var link = $(this);
      $("#" + link.attr("data-update")).html(status);
    });
});
</script>

<%= link_to "hoge",hoge_path, :remote => true, "data-type" => "html", "data-update" => "hoge_id" %>

linkにdata-updateという属性を持たせて、それの値に更新したいIDを指定します。jQueryの方ではdata-updateという属性を持つものに対して、Ajaxで返ってきたレスポンスでdata-updateで指定したIDのhtmlを書き換えるという処理をさせてます。
このノリで行けば、:loadingや:beforeも行けそうな気がします。

これで良いのかわからないですが、ひとまず動いたので個人的には良しとします。他にいい方法があったら教えてください。