发新话题
打印

[Rails插件] will_paginate array?

本主题由 admin 于 2008-3-16 16:10 移动

will_paginate array?

http://www.desimcadam.com/archives/8

Today I started putting pagination in the app that I have been working on. Based on recommendations from Obie I decided to use “will_paginate”, a rails plugin for pagination put out by the err the blog guys. It worked amazingly and the view helper was great! I really like the fact that I can apply the same look and feel to all page pagination throughout the app… well umm.. until I wanted to add pagination to a collection not generated from a finder or association. Since I really wanted everything to look the same and behave the same I did the following little trick so that you can call paginate on a plain old array.
复制内容到剪贴板
代码:
class Array
  def paginate(page=1, per_page=15)
    pagination_array = WillPaginate::Collection.new(page, per_page, self.size)
    start_index = pagination_array.offset
    end_index = start_index + (per_page - 1)
    array_to_concat = self[start_index..end_index]
    array_to_concat.nil? ? [] : pagination_array.concat(array_to_concat)
  end
end
Before folks say anything about the above code.. yes I know it could be more concise if I didn’t use all the local variables but I wanted it to be really clear what I was doing here so.. leave it alone.

Now basically you can say

myarray.paginate(params[:page], per_page)

If you want to see it work yourself feel free to run this spec.
复制内容到剪贴板
代码:
require File.dirname(__FILE__) + ‘/../spec_helper’

describe ‘Given we call paginate on an array’ do
  it ’should return an array containing the first 3 elements of the org array when page = 1 and per_page_count = 3′ do
    array = [”a”,”b”,”c”,”d”,”e”]
    current_page = 1
    show_per_page = 3
    expected_array = [”a”, “b”, “c”]
    (array.paginate(current_page, show_per_page)).should == expected_array
  end

  it ’should return an array containing the last 2 elements of the org array when page = 2 and per_page_count = 3′ do
    array = [”a”,”b”,”c”,”d”,”e”]
    current_page = 2
    show_per_page = 3
    expected_array = [”d”, “e”]
    (array.paginate(current_page, show_per_page)).should == expected_array
  end

  it ’should return an array containing all the elements of the org array when page = 1 and per_page_count = 5′ do
    array = [”a”,”b”,”c”,”d”,”e”]
    current_page = 1
    show_per_page = 5
    expected_array = [”a”,”b”,”c”,”d”,”e”]
    (array.paginate(current_page, show_per_page)).should == expected_array
  end

  it ’should return an array containing all the elements of the org array when page = 1 and per_page_count greater than org number of elements i.e = 6′ do
    array = [”a”,”b”,”c”,”d”,”e”]
    current_page = 1
    show_per_page = 6
    expected_array = [”a”,”b”,”c”,”d”,”e”]
    (array.paginate(current_page, show_per_page)).should == expected_array
  end

  it ’should return an empty array if you ask for a page that does not exist’ do
    array = [”a”,”b”,”c”,”d”,”e”]
    current_page = 3
    show_per_page = 5
    expected_array = []
    (array.paginate(current_page, show_per_page)).should == expected_array
  end

  it ’should return an empty array if you ask for a negative page number’ do
    array = [”a”,”b”,”c”,”d”,”e”]
    current_page = -1
    show_per_page = 5
    expected_array = []
    (array.paginate(current_page, show_per_page)).should == expected_array
  end

  it ’should return an empty array if you ask for a negative per_page number’ do
    array = [”a”,”b”,”c”,”d”,”e”]
    current_page = 1
    show_per_page = -5
    expected_array = []
    (array.paginate(current_page, show_per_page)).should == expected_array
  end
end
will_paginate已经给Array添加了paginate(page = 1, per_page = 15)
方法,并可以配合其view helper使用(如果不嫌太费内存的话),用法就如Model.paginate()的结果一样。

TOP

8th Apr, 2008
自定义will_paginage输出

will_paginate是Rails中比较常用的分页插件,但是有时候我们可能想要自定义它的输出,这可以通过扩展WillPaginate::LinkRenderer类来实现,比如,下面的renderer将会去除Next和Previous链接(来自这里):

class CustomPaginationRenderer < WillPaginate::LinkRenderer
  def to_html
    links = @options[:page_links] ? windowed_links : []   
    html = links.join(@options[:separator])
    @options[:container] ? @template.content_tag(:div, html, html_attributes) : html
  end  
end

要在view中使用这个自定义的renderer,只需要加上:renderer参数即可:


<%= will_paginate @items, ;:renderer => 'CustomPaginationRenderer' %>

下面给出一个更复杂的自定义Renderer,它会在分页链接后显示一个文本框,以及一个‘Goto’按钮,允许用户直接跳转到某一页:


class CustomPaginationRenderer < WillPaginate::LinkRenderer
  @@id = 1
  def to_html
    links = @options[:page_links] ? windowed_links : []
    # previous/next buttons
    links.unshift page_link_or_span(@collection.previous_page, 'disabled', @options[:prev_label])
    links.push    page_link_or_span(@collection.next_page,     'disabled', @options[:next_label])
    html = links.join(@options[:separator])
    html += goto_box
    @options[:container] ? @template.content_tag(:div, html, html_attributes) : html
  end
  private
  def goto_box
    @@id += 1
    @@id = 1 if @@id > 100
  <<-GOTO
    <input type="text" maxlength="5" size="3" id="page#{@@id}" />
    <input type="submit" onclick="goto_page#{@@id}()" value="Goto"/>
    <script type="text/javascript"&gt
      function goto_page#{@@id}()
      {
        page = Number($('page#{@@id}').value)
        total = #{total_pages}
        if(page < 1 || page > total)
        {
          alert('Please enter a number between 1 and ' + total + '!')
          return;
        }
        var link = '#{@template.url_for(url_options("_page"))}'
        var new_link = link.replace("_page", page)
        window.location.assign(new_link)
      }
    </script>
    GOTO
  end
end

@@id的作用是因为一个view中有可能多次调用will_paginate,需要对inputbox进行区分,这个renderer还用到了一些继承自WillPaginate::LinkRenderer的方法:

    * url_for(page), 返回指向某页的链接,比如url_for(1) => ‘/posts?page=1′
    * total_pages, 返回总页数
    * page_link_or_span,返回指向某页面的链接

更多方法可以在WillPaginate的view_helper.rb中找到。

TOP

发新话题