Search code examples
ruby-on-railsrubyactiverecordpg

Displaying multiple copies of one activerecord object


I am displaying a list of articles and using will_paginate gem and endless scrolling. This is all working fine.

My problem, however, is that I am occasionally getting multiple copies of the same article in the view. It doesn't happen all the time, and nor with every article, but enough that it is bloody annoying.

I know there is no duplication in the database, and so the problem occurs in the rendering somehow.

Here is my controller:

@articles = Article.order("date_published DESC", "RANDOM()").paginate(:page => params[:page],:per_page => 10)  

I am trying somehow to include the distinct or uniq method, but it seems I can't use either with the order method.

I am using pg for db.

Any help would be greatly appreciated!


Solution

  • The issue arises with your sub-sort, RANDOM().

    Imagine I have these posts:

    id  published  title
    ----------------------
     1  1/1/1970   One
     2  1/2/1970   Two
     3  1/2/1970   Three
     4  1/3/1970   Four
    

    If I request page one (with a page size of 2), I can either get 4 and 3, or 4 and 2. Now, if I request page 2 I can either get 3 and 1 or 2 and 1. This is because of the RANDOM() sub-sort. The first query may pull the page from this result:

    id  published  title
    ----------------------
     4  1/3/1970   Four
     3  1/2/1970   Three
     2  1/2/1970   Two
     1  1/1/1970   One
    

    Which is 4 and 3, but this result is also possible:

    id  published  title
    ----------------------
     4  1/3/1970   Four
     2  1/2/1970   Two
     3  1/2/1970   Three
     1  1/1/1970   One
    

    Which is 4 and 2. And either of these results will also result in a different page 2 as well. This random sort is the cause of your duplicates, you need to use consistent sorts or manage removal of duplicates in some other way. Such as:

    @articles = Article.where.not(id: list_of_already_fetched_ids).order("date_published DESC", "RANDOM()").paginate(:page => params[:page],:per_page => 10)
    

    NOTE: where.not is usable in Rails 4, if you are not using Rails 4 you'll need to find another way to implement that filter.