Rails 3 + will_paginate 3.0.pre2でAjax対応なリンクを生成する

初めまして.morimorihogeといいます.Webアプリの開発をすることが多いので,主にそっち系の記事を書いていくことになるかと思いますので,よろしくお願いします.

さて,Rails 3でwill_paginateを使っているときに,remote => true的なことをやりたくてググっていたのですが,世の中で見つかる事例がwill_paginate 2系の記事ばかりだったので,自己解決した結果を書いておきます.ちなみにRails 3.0.3 + will_paginate 3.0.pre2で動作確認しています.

具体的にはどういう事かというと,will_paginateを使うと,

<%= will_paginate @posts %>

としたものはaタグのリンクリストになるのですが,これは通常のaタグであるため,ページ遷移が発生します.
具体的には,コンテンツをAjaxを使って作っていて,

  • views/home/index.html.erb
<script type="text/javascript">// <![CDATA[
$(function(){
    $.ajax({
      type: 'GET',
      url: '<%= posts_url %>',
      dataType: 'script'
    });
});
// ]]></script>
  • controllers/posts_controller.rb
def index
  @sort_field = params[:sort] || “updated_at”
  @sort_order = params[:order] || :desc
  @posts = Post.paginate(
    :page => params[:page], :per_page => params[:per_page] || 20,
    :order => “#{@sort_field} #{@sort_order}”
  )
  respond_to do |format|
  format.js
  end
end
  • views/posts/index.rjs
page.replace_html ‘posts_table’, :partial => ‘posts/list’,
:locals => {:posts => @posts}
  • views/posts/_list.html.erb
<%= will_paginate @posts %>

<%= will_paginate @posts %>

みたいなコードを書いていた時にwill_paginateに出力してもらいたいリンクは,以下の様なdata-remote, data-remote属性が設定されたaタグであってほしいわけです..

<a href="/posts?page=1" data-remote="true" data-method="get">1</a>

通常のlink_toヘルパを使えば以下の様になります.Rails3からはlink_to_remoteではなくて:remote => trueを使うようになっていますね.

<%= link_to posts_path(:page => 1), :remote => true %>

この辺りの解決策をぐぐると,この辺りこの辺りが出てきたのですが,いくらやってもうまく行かず,結局will_paginateのソースを追いかけてみたところ,そもそも3.0.pre2ではpage_linkメソッド自体が廃止されていました.

というわけで,will_paginate 3.0.pre2では,以下のようにすればOKです.

  • lib/remote_pagination_list_link_renderer.rb
class RemotePaginationListLinkRenderer < WillPaginate::ViewHelpers::LinkRenderer
  private

  # :remote => true
  def link(text, target, attributes = {})
    if target.is_a? Fixnum
      attributes[:rel] = rel_value(target)
      target = url(target)
    end
    attributes[:href] = target
    attributes[“data-remote”] = true
    attributes[“data-method”] = :get
    tag(:a, text, attributes)
  end
end
  • views/posts/_list.html.erb
<%= will_paginate @posts,
:renderer => RemotePaginationListLinkRenderer %>

(Post一覧は省略)

<%= will_paginate @posts,
:renderer => RemotePaginationListLinkRenderer %>

これで,:renderer => RemotePaginationListLinkRendererを付けて呼び出したwill_paginateはAjax呼び出しになります.

ちなみに,毎回Rendererを指定するのが面倒であれば,以下の設定をする手もあります.ただ,この場合全てのwill_paginateがAjax呼び出しになるので注意です.

  • config/initializers/will_paginate.rb
# for :remote option
WillPaginate::ViewHelpers.pagination_options[:renderer] = 'RemotePaginationListLinkRenderer'

ではでは〜

デザインも頼めるシステム開発会社をお探しならBPS株式会社までどうぞ 開発エンジニア積極採用中です! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

morimorihoge

高校卒業後,学生をやりながらずっとWebアプリ開発に携わってきました.2010くらいまではPHP/Symfonyプログラマでしたが,それ以降のWeb開発はRailsほぼ一本に宗旨替えしました.開発とは別にサーバ構築・運用も10年以上やってきているので,要件定義から設計・実装・環境構築・運用まで一通り何でもこなせます.開発以外では季節により大学でWebサービス開発やプログラミング関連の非常勤講師もしており,技術の啓蒙・教育にも積極的に関わっています.最近はPM的な仕事が増えていますが,現役開発者としていつでも動ける程度にはコードもサーバも弄る日々を送っています.AWS 認定ソリューションアーキテクト – アソシエイトレベル取りました

morimorihogeの書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

ActiveSupport探訪シリーズ