Joe Essey
Joe Essey

Reputation: 3527

How to paginate elements of an array after sorting on it?

I've got a controller method that sorts elements by a derived attribute. I can print to the view as long as I don't attempt to paginate. When I call @foos = @foos.page params[:page] I get the following error: undefined method 'page' for #<Array:...>

Can anyone provide some guidance here? Thanks.

Here's the whole controller method:

def index_by_capacity
    if current_user.is_view_major?
      @foos = Foo.major_attr(:name)
    else
      @foos = Foo.order(:name)
    end


  @foos = @foos.sort_by! {|a| a.capacity_available.to_i }
  @total_foos = @foos.count

  @foos = @foos.page params[:page]

  respond_to do |format|
    format.html
    format.json { render json: @foos }
  end
end

Upvotes: 4

Views: 1027

Answers (2)

MrYoshiji
MrYoshiji

Reputation: 54882

  • The .sort_by! method returns an Array, which has no method page (a ruby Array can't be paginated, you would have to implement it yourself or use an external lib).

  • The pagination works on ActiveRecord::Relation objects, returned by queries like .where or .order

  • In you case, you should do an order at the DB-level (faster than doing a sort via Ruby):

    @foos.order(:capacity_available)
    
  • If the capacity_available attribute is a String (not an Integer), you can CAST it as an INT:

    @foos.order('CAST(capacity_available AS INT) ASC')
    

(You may need to edit the CAST() function, it should work on PostGreSQL, not sure about MySQL)

Upvotes: 5

Josh
Josh

Reputation: 5721

If you want to continue using an array instead of an active record relation object, you can simply include WillPaginate::Collection.

From WillPaginate Documentation

Previously, all objects returned from paginate methods were of WillPaginate::Collection type. This is no longer true; in Active Record 3, the paginate and page methods return a Relation that is extended to look like a WillPaginate::Collection. Similarly, DataMapper returns a regular DataMapper::Collection that is also extended.

Both ActiveRecord::Relation and DataMapper::Collection are lazy arrays in the way that they don't execute any SQL queries until the point when data is needed. This makes them better than ordinary arrays.

The WillPaginate::Collection class is still available, however, and mostly unchanged.

The Array#paginate method still exists, too, but is not loaded by default. If you need to paginate static arrays, first require it in your code:

require 'will_paginate/array'

Upvotes: 1

Related Questions