Rails3 で Ajax (link_to_remote + will_paginate 対応)

Rails3 で Ajax 対応をする場合は下記のような感じで view を書いて、リクエストを受け取る側の Controller 等でも JavaScript を書かないと動かないようです。

<%= link_to('参照',  {:action => 'show'}, :remote => true) %>

可能であればこれを勉強して Rails3 っぽく書きたいところなのですが、とりあえず Rails 2.x の link_to_remote に逃げる方法です。
(Rails3 の Ajax + RJS は後で勉強するつもりです(^^;)

まずは、prototype_legacy_helper を vendor/plugins に配置します。

$ cd vendor/plugins
$ git clone git://github.com/rails/prototype_legacy_helper.git

これで view 上で link_to_remote が動作するようになるので、下記のような感じで記述できます。

<%= link_to_remote(
  '参照',
  {
    :url => {:action => 'show'},
    :update => 'update_target',
    :loading => "showLoading('big', 'update_target')",
  }
) -%>

<div id="update_target">ここを書き換えたい</div>

サーバからのレスポンスを待っている間は Alax っぽくロード中の画像を出したいので、:loading で showLoading を呼び出しています。
これは、下記の JavaScript を public/javascripts/application.js 等に書いておきます。

/*
 * ロード画面を出力する
 */

function showLoading(load_image_size, load_target)
{
  // 画像オブジェクトの作成
  img_element = document.createElement('img');
  img_element.src = load_image_size == 'big' ?
                    '/images/ajax-loader.gif' :
                    '/images/ajax-loader-small.gif';
  img_element.align = 'center';

  // センタリングオブジェクト
  center_element = document.createElement('center');
  center_element.appendChild(img_element);

  // 画像を表示するメソッド
  var output_loading = function(load_image, target_place) {
    target = document.getElementById(target_place);
    while (target.hasChildNodes()) {
      target.removeChild(target.firstChild);
    }
    target.appendChild(load_image);
  }

  // ロード画像を表示する場所が複数か否かの分岐
  if (load_target instanceof Array) {
    for (var i = 0; load_target[i]; i ++) {
      output_loading(center_element, load_target[i]);
    }
  } else {
    output_loading(center_element, load_target);
  }
}

/images/ajax-loader.gif や /images/ajax-loader-small.gif などの画像は Ajaxload - Ajax loading gif generator で自分好みの画像を作成すると良い感じになります。
これで link_to_remote での Ajax リクエストが実行できるようになります。
FORM から Ajax リクエストを実行したい場合は form_remote_tag を使用すれば、同様の動作を行うことが可能です。


ただし、prototype_legacy_helper は will_paginate に対応していないので別途対応が必要になります。
まず、app/helpers/remote_link_renderer.rb に下記のような内容を記述します。
(こちらは、id:donghai821 さんの記事を参考にさせていただきました)

class RemoteLinkRenderer < WillPaginate::LinkRenderer
  private

  def link(text, target, attributes = {})
    if target.is_a? Fixnum
      page = target
      target = url(target)
      target[:url][:page] = page
    end

    @template.link_to_remote(text, target, attributes)
  end

  def url(page)
    @base_url_params ||= begin
      url_params = base_url_params
      merge_optional_params(url_params)
      url_params
    end

    url_params = @base_url_params.dup
    add_current_page_param(url_params, page)

    return url_params
  end
end

次に will_paginate を下記のように記述すると、ページ送りも Ajax で動作するようになります。

<%= will_paginate(
  @users,
  :renderer => RemoteLinkRenderer,
  :params => {
    :url => {:action => 'show'},
    :update => 'update_target',
    :loading => "showLoading('big', 'update_target')",
  },
  :previous_label => '<-',
  :next_label => '次 ->'
) -%>