16th Sat

pagination_scope

named_scopeによるPagination を行うためのGemを作りました。 通常はwill_paginateを利用するほうがいいと思いますが、 :joinsを含む複雑なnamed_scopeを介してpaginationを行いたい場合には、 利用すると便利かもしれません。

pagination_scope

使い方

まず、モデルクラスの中でincludeします。

   1  class Post
   2    include PaginationScope
   3  end

これによって、Postクラスにpaginateというnamed_scopeが作成されます。

続いて、Paginationを利用したいコントローラのアクションメソッド内で、

   1  class PostsController < ApplicationController
   2    def index
   3      @posts = Post.not_deleted.paginate(params[:page], 10)

のようにScopeを取得します。

続いて、Viewで以下のようにPagination用HTMLを生成します。

   1  <%= paginate @posts %>

paginateメソッドは PaginationScope によって導入されるViewヘルパーです。

posted by Png genki on Sat 16 Aug 2008 at 23:25

Railsアプリケーションでpaginationといえば、 will_paginate等のプラグインやGemを使うのが一般的だと思います。 しかし、named_scopeでjoinsを使った場合にうまく paginationができなかったので、 named_scopeだけを使ってpaginationする方法を考えてみました。

まずは以下のようなnamed_scopeを作ります。 以下の例はPostクラスで宣言される事を想定しています。

   1  named_scope :paginate, proc{|page, per_page|
   2    {:offset => per_page*((page || 1).to_i - 1),
   3     :limit => per_page}} do
   4      def count
   5        proxy_scope.count(:group => 'posts.id').size
   6      end
   7      def num_pages
   8        (count.to_f/proxy_options[:limit]).ceil
   9      end
  10      def page
  11        proxy_options[:offset]/proxy_options[:limit] + 1
  12      end
  13      def pages(window = 5, left = 2, right = 2)
  14        (1..num_pages).inject([]) do |result, i|
  15          i <= left || (num_pages - i) < right ||
  16            (i-page).abs < window ? result << i :
  17              (result.last.nil? ? result : result << nil)
  18        end
  19      end
  20    end

countを再定義しているのは、:joinsを含む別なnamed_scopeをチェーンした時に、正しいcountを求めるためです。

コントローラでは、以下のようにScopeを取得します。

   1  @posts = Post.paginate(params[:page], 5)

Viewでは以下のように記述します。

   1  <% if @posts.page > 1 %>
   2    <%= link_to '&laquo; Newer',
   3        url_for(:page => @posts.page - 1) %>
   4  <% else %>
   5    &laquo; Newer
   6  <% end %>
   7  <% @posts.pages.each do |i| %>
   8    <% if i.nil? %>
   9      ...
  10    <% elsif i == @posts.page %>
  11      <%= i %>
  12    <% else %>
  13      <%= link_to i, url_for(:page => i) %>
  14    <% end %>
  15  <% end %>
  16  <% if @posts.page < @posts.num_pages %>
  17    <%= link_to 'Older &raquo;',
  18        url_for(:page => @posts.page + 1) %>
  19  <% else %>
  20    Older &raquo;
  21  <% end %>

posted by Png genki on Sat 16 Aug 2008 at 21:10
Contents
pagination_scope
named_scopeによるpagination
Comments
dsjf: https://gist.github.com/6bf1bf2c3cbb5eb6e7a7 これ... '13-1
瀧内元気: おお、チェックしてみます。thx! '11-12
overisland: Reeder for iPhone もこの UI を実装していますね。 '11-12
瀧内元気: その情報は見たのですが、以下のサイトによると、現在はまた必要になってるっぽいんですよね。 ... '11-12
tkawa: http://devcenter.heroku.com/articles/rails31_he... '11-12
Services from s21g
twpro(ツイプロ)
Twitterプロフィールを快適検索
地価2009
土地の値段を調べてみよう
MyRestaurant
自分だけのレストラン手帳
Formula
ブログに数式を埋め込める数式コミュニティ