#66 ✓invalid
Andreas Neuhaus

Paginate custom finders

Reported by Andreas Neuhaus | July 26th, 2007 @ 07:31 PM

I'm having problems using will_paginate with a custom finder method in my models:

class User < AR::Base
  def find_all_special (options = {})
    with_scope(:find => {:conditions => "...", :order => "..." }) do
      find(:all, options)
    end
  end
end

Retrieving records by using @users=User.paginate_special(...) does work, because using paginate_xyz calls find_all_xyz and adds offset/limit options to retrieve the records. However the paginate method does not retrieve the correct record count. It uses the count method but isn't able to apply the scope that could be applied in a custom finder method. Therefore the will_paginate helper displays more pages than actually exist.

Because I want to keep the search conditions within my model classes, I solved this problem by adding a count_special method which returns the number of records by using "count" within the proper scope. However now I have to specify :total_entries => User.count_special whenever using paginate_special; which isn't very DRY (and I tend to forget to add this option sometimes)

It would be nice if will_paginate would automatically use a custom counter method if such one exists (like automatically using count_special if paginate_special is used).

Or does somebody else maybe know a better way to paginate cutstom finder methods in a DRY way?

Comments and changes to this ticket

  • Chris Wanstrath

    Chris Wanstrath July 26th, 2007 @ 07:31 PM

    • State changed from “new” to “open”
    • Assigned user changed from “Chris Wanstrath” to “Mislav”
  • Andreas Neuhaus

    Andreas Neuhaus July 26th, 2007 @ 07:31 PM

    I wrote up a more detailed description of this problem in a posting in my Blog

  • Mislav

    Mislav July 26th, 2007 @ 07:31 PM

    • State changed from “open” to “invalid”

    So, you would like this:

    class User < AR::Base
      def self.find_all_special(options = {})
        with_scope(:find => { :conditions => "...", :order => "..." }) do
          find(:all, options)
        end
      end
    
      def self.count_special(options = {})
        with_scope(:find => { :conditions => "...", :order => "..." }) do
          count(options)
        end
      end
    end
    
    User.paginate_special(:page => 1)
    

    Right?

    But don't you see that you didn't manage to stay DRY anyway? It is because you're using with_scope totally wrong. Isn't this much better?

    class User < AR::Base
      def self.paginate_special(options)
        with_scope(:find => { :conditions => "...", :order => "..." }) do
          paginate(options)
        end
      end
    end
    
    User.paginate_special(:page => 1)
    

    Or even this

    class Developer < User
      def self.with_poor_ones(&block)
        with_scope :find => { :conditions => ['salary <= ?', 80000], :order => 'salary' } do
          yield
        end
      end
    end
    
    Developer.with_poor_ones do
      Developer.paginate :page => 1
    end
    

    But this last example may be frowned upon by Rails purists. Better stick with the middle example.

  • Andreas Neuhaus

    Andreas Neuhaus July 26th, 2007 @ 07:31 PM

    Thanks, Mislav. Indeed using a custom paginate method would solve the problem - however, only if you need just the paginate method. If you also need the non-paginated custom finder somewhere, you'd become non-DRY again (more on that in my reply to your comment post in my blog).

    Another idea came into my mind: will_paginate is easy to use, because it's unobstrusive. You write models like before and get pagination on top by installing will_paginate. It would be nice if that could also be possible with custom finders. It almost works already - except that the wrong count of total records is retrieved. To get the right count, all that would be required, is to let the custom finder build the SQL conditions like before and use it with count ('select count(*)') instead of find ('select *'). I'm not sure how AR works and if this is even possible without chaning AR itself, but that would be a great will_paginate feature.

  • Mislav

    Mislav July 26th, 2007 @ 07:31 PM

    At first I thought it was a good feature, yes. But then I though about

    how this custom counters would be implemented, and I realized users

    would have to duplicate logic in finders and corresponding counters.

    So, will_paginate would support bad coding practice then.

  • Adam Cohen

    Adam Cohen August 23rd, 2007 @ 11:33 PM

    I echo your concerns Zargony, I'd love to see support for custom complex finders as well. Is this a possibility in the future Mislav?

  • Mislav

    Mislav August 24th, 2007 @ 12:14 AM

    Will Paginate now supports the scope_out plugin. Continue the discussion on the blog...

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile ยป

Everyone's favorite Ruby library for pagination of practically anything!

Referenced by

Pages