rubyroyd blog

ActiveResource pagination

I didn’t find any good article on how to do pagination on ActiveResource, so here’s my 2ยข. Basically, I wanted to do as less changes to the server as possible. As we already using pagination on the server side, the only change was to add info about total number of items and items per page to the server’s xml response. This is needed by client to properly build pagination links inside it’s view.

Server controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

  def index
    @airports = Airport.paginate(:page => params[:page],
                                            :per_page => APP_CONFIG['airports_per_page'])

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { @airports << {
                              :pagination_members_total => @airports.total_entries,
                              :pagination_members_per_page => APP_CONFIG['airports_per_page']
                               }
                    render :xml => @airports
                  }
    end
  end

There’s no pagination done at the client side, we just need to extract the pagination parameters and pass them to will_paginate view helper.

Client controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

  def index
    current_page = params[:page] || 1
    total_members, per_page = 0
    
    airports = Airport.find(:all, :params => { :page =>  current_page})
    airports.each_index{|x| 
      if airports[x].respond_to?(:pagination_members_total) && airports[x].respond_to?(:pagination_members_per_page)
        total_members = airports[x].pagination_members_total
        per_page = airports[x].pagination_members_per_page
        airports.delete_at x
        break
      end
    }

    @airports = WillPaginate::Collection.create(current_page, per_page, total_members) do |pager|
      pager.replace airports
    end
  end 

Client view (same as on server)

1
2

                <%= will_paginate @airports %>

Looks a bit ugly, but works. Please let me know if there’s a better solution.

  1. Igor F says:

    I realized that it can be done with additional server headers.
    Look here https://github.com/Fivell/activeresource-response

  2. CantuMadeleine34 says:

    I had a dream to start my own business, however I did not earn enough amount of money to do this. Thank goodness my colleague advised to take the <a href="http://goodfinance-blog.com/topics/home-loans">home loans</a>. Thus I took the short term loan and realized my old dream.

  3. Sidu says:

    PoxPaginate should take care of this. http://github.com/c42/pox_paginate

  4. Jim says:

    Awesome! I've wrapped this solution into a separate file. require it in your environment.rb file and you should be able to call...

    AnyActiveResource.paginate ... in your client

    and

    AnyActiveRecord.paginate_for_remote ... in your server

    Doesn't really improve on the code just moves the ugliness out of the controllers. :-)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    
    class ActiveResource::Base
      def self.paginate(*args)
        total_members, per_page = 0
    
        options = args.detect{|a| a.is_a?(Hash) && a.has_key?(:params)}
        if options
          params = options[:params]
        else
          return
        end
      
        current_page = params[:page] || 1
        params[:per_page] ||= 30
    
        rs = find(*args)
    
        if rs[0].respond_to?(:pagination_members_total) && rs[0].respond_to?(:pagination_members_per_page)
          total_members = rs[0].pagination_members_total
          per_page = rs[0].pagination_members_per_page
          rs.delete_at 0
        end
        
        WillPaginate::Collection.create(current_page, per_page, total_members) do |pager|
          pager.replace rs
        end
      end
    end
    
    class ActiveRecord::Base
      def self.paginate_for_remote(*args)
        params = args.detect{|a| a.is_a?(Hash) && a.has_key?(:per_page)}
        
        if params
          per_page = params[:per_page]
        else
          return
        end
        
        rs = paginate(*args)
        rs = [{:pagination_members_total => rs.total_entries,
                :pagination_members_per_page => per_page}] + rs
      end
    end
    

  5. Use a array add to lessen the loop says:

    @airports = [{
    :pagination_members_total => @airports.total_entries,
    :pagination_members_per_page => APP_CONFIG['airports_per_page']
    }] + @airports

    Then
    if airports[0].respond_to?(:pagination_members_total) && airports[0].respond_to?(:pagination_members_per_page)
    total_members = airports[0].pagination_members_total
    per_page = airports[0].pagination_members_per_page
    airports.delete_at 0

    Thanks for the help too....

  6. ettober says:

    Thanks a million for this!

Post a comment


(lesstile enabled - surround code blocks with ---)

simple_captcha.jpg
(type the code from the image)