Skip to content

Multi model pagination in a single feed #351

Closed
blazeeboy opened this Issue Jan 15, 2014 · 3 comments

3 participants

@blazeeboy

in my last project i stuck into a problem, i had to paginate multiple models with single pagination in my search functionality.
it should work in a way that the first model should appear first when the results of the first model a second model should continue the results and the third and so on as one single search feed, just like facebook feeds.
this is the function i created to do this functionality

    def multi_paginate(models, page, per_page)

      WillPaginate::Collection.create(page, per_page) do |pager|

        # set total entries
        pager.total_entries = 0
        counts = [0]
        offsets = []
        for model in models
              pager.total_entries += model.count
              counts << model.count
              offset = pager.offset-(offsets[-1] || 0)
              offset = offset>model.count ? model.count : offset 
              offsets << (offset<0 ? 0 : offset)
        end

        result = []
        for i in 0...models.count
              result += models[i].limit(pager.per_page-result.length).offset(offsets[i]).to_a
        end

        pager.replace(result)
      end

    end

models should be an array of activeRecord models that respond to limit, offset, count methods.
i added this function as private method to my controller and used it in my search method.
any enhancements would be great,
also is there any rules to contribute to will_paginate ? should i write tests -this is my ugly beast practice- or should i add the method, and commit, pull request and done?

@mislav
Owner
mislav commented Feb 3, 2014

Hi, sorry for the late reply.

I'm glad you solved your problem, but this is something specific to your application and wouldn't be so useful to be in the will_paginate library itself. I can see that you wrote it very well to work with multiple ActiveRecord models, but most people don't need to paginate multiple models in a single collection. It's not a very common use case.

But if somebody ever searches the issue tracker for something like this, they'll be able to find your code snippet and copy-paste it to their app as well. Thanks for sharing.

@mislav mislav closed this Feb 3, 2014
@blazeeboy

small fix, when a model did'nt have count the offset get miss calculated, so we have to drop any model that doesn't have results.

    def multi_paginate(models, page, per_page)

      WillPaginate::Collection.create(page, per_page) do |pager|

        models.keep_if {|m| m.count>0 }
        # set total entries
        pager.total_entries = 0
        counts = []
        offsets = []
        limits = []
        for model in models
              pager.total_entries += model.count
              counts << model.count
              offset = pager.offset-offsets.sum
              offset = offset>model.count ? model.count : offset 
              offsets << (offset<0 ? 0 : offset)
        end

        result = []
        for i in 0...models.count
              limits << pager.per_page-result.length
              result += models[i].limit(pager.per_page-result.length).offset(offsets[i]).to_a
        end

        puts '-'*100
        print counts,"\n",offsets,"\n",limits,"\n"
        print "pages offset:", pager.offset,"\n"
        puts '-'*100

        pager.replace(result)
      end

    end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.