16

I'm using will_paginate for pagination, which has been working well so far, except for this one thing.

If I try to paginate a scope, for instance

class User < ActiveRecord::Base

    named_scope :scope, lambda { etc }

end

User.scope.paginate({:page => params[:page], :per_page => 10})

That will tell me paginate is an undefined method. I'd rather not have to use a second solution for only this scope, is there something I can do here?

Lowgain
  • 3,254
  • 5
  • 27
  • 30

4 Answers4

9

Lowgain, klew's version should work out of the box. In your version you should write:

User.scope.paginate :page => params[:page], :per_page => 10

I prefer another approach to pagination. It allows to make controller more clean and encapsulates pagination at model level, for e.g.:

class Property < ActiveRecord::Base
  named_scope :all_properties, lambda {{ :order => "name asc" }}

  def self.admin_properties(page = 1)
    self.all_properties.paginate(:page => page, :per_page => Settings.admin.per_page)
  end
end

And in a controller pretty clear code:

class Admin::PropertiesController < Admin::AdminController
  def index
    @properties = Property.admin_properties(params[:page])
  end
end

p.s: Settings.admin.per_page - this is Searchlogic settings.

Voldy
  • 12,829
  • 8
  • 51
  • 67
  • Hmm, this is interesting! Is there any kind of noticeable performance drawback to doing it this way, as it is paginating every property? – Lowgain May 09 '10 at 19:50
  • How can it paginate every property? :) Not every, but all. Named scope *all_properties* is a kind of class method (not instance!). So when we call *self.all_properties*, we receive all properties from this named scope. Then we paginate them. Self means class Property itself - not object of class Property. – Voldy May 10 '10 at 08:13
2

I have a named_scope defined like this:

 named_scope :look_for, lambda { |search| bla;bla;bla }

I call it:

 Person.look_for(params[:search]).paginate :page => params[:page]

And it works. Maybe you need some parameter to your scope?

klew
  • 14,837
  • 7
  • 47
  • 59
  • hmm, what kind of parameter would you expect? the scope does appear to work outside of being paginated – Lowgain May 07 '10 at 23:45
  • If your scope takes parameter, then you should give one. If not, then don't ;). My example is with parameter. – klew May 08 '10 at 08:48
2

Kind of a weird solution, but

User.scope.find(:all).paginate :page => params[:page], :per_page => 10

works?

Lowgain
  • 3,254
  • 5
  • 27
  • 30
1

Lowgain, it doesn't sound like you are, but just to make sure -- you aren't actually doing tests with a named_scope named scope right? Because scope is an existing method and using that as your scope name causes an error (and an infinite loop).

EDIT:

Does your named_scope happen to include a :limit clause? I just started having a similar problem. I have a model Response which belongs_to User, with a named scope something like this:

named_scope :top, lambda { |limit| {
            :limit => limit,
            :order => 'total_score DESC' }}

And I am seeing results in the console such as this:

?> u = User.find 1
?> u.responses.length
=> 9
?> u.responses.paginate(:page => 1, :per_page => 5).length
=> 5
?> u.responses.top(3).length
=> 3
?> u.responses.top(3).paginate(:page => 1, :per_page => 5).length
=> 5

Yikes! How can my top 3 paginate to produce more than 3 rows? Per your example I tried your find(:all) trick with similar results:

?> u.responses.top(3).find(:all).paginate(:page => 1, :per_page => 5).length
=> 3

This looks like a bug in named_scope, because I can take will_paginate out of the picture and get similar mayhem to occur:

?> u.responses.top(3).length
=> 3
?> u.responses.top(3).size
=> 9                       <-- .size produces wrong answer
?> r = u.responses.top(3)
?> r.size
=> 3                       <-- correct when result assigned to var

So far, this only appears to happen when I am using MySQL. I think I read another post on StackOverflow where someone had a similar problem using .size with AR results and MySQL, and the solution was to always use .length on their AR results. I have tried modifying will_paginate to replace all instances of .size with .length, but alas it was not that simple, but I suspect that this or a similar issue is somehow affecting will_paginate.

For the time being, I am using your find(:all) trick to hack around this.

MikeJ
  • 1,164
  • 2
  • 8
  • 15
  • Just realized I blogged about this same thing 2 months ago, forgot about it, then "rediscovered" it today. I hate becoming senile! – MikeJ Jul 04 '10 at 06:29