Making a pagination based infinite scroll as a beginner — on the backend.

Berel Levy
3 min readOct 26, 2020

This is not a definitive guide and it’s also not optimal, however, it works and it explains the concept well.

Tech stack: Ruby on Rails for the backend, React and Redux on the frontend (stay tuned).

Note: cursor based navigation is better, but I’ve only just learned about it, so when I implement it, I’ll write a post about it.

The first thing we need to do is paginate the data on the back end. (paginate = divide the data up into pages.)

so when our posts controller requests an index of posts from model, it needs to specify which page it wants.

The model receives this request and needs to know one more thing, how many items to display per page. For now we’ll keep that hardcoded.

Bonus points if you comment how the sql query method chain can be optimized.

Let’s explain some of the code above.

line 2. page_qty = 5 sets the amount of items each ‘page’ has.

Line 3. offset = page_num * page_qty is how we’ll tell our database exactly which record to begin with. I’ll explain this in detail in the next two lines of code.

Line 4. There’s a lot happening on line 4, I’ll assume you are familiar with Rails’ sql methods and I’ll explain what each one accomplishes in our context. One important point that I’ll make here is that chaining multiple sql methods still results in one sql query. That’s one of the great advantages of Rails’ sql query methods. now let’s break it down.

Post.order(updated_at: :desc): creates a sql query that looks something like this:

SELECT "posts".* FROM "posts" ORDER BY "posts"."updated_at" DESC

pretty neat, no?

.where(user_id: followees_ids): A little background here, the followees_ids method returns an array of ids of users that our current user follows which is his feed, by definition. This is probably not the best way to make the query, but it works, and it illustrates an important point; that you can pass an array of values to the where method. This is super cool and our sql query is now changed, and it looks like this:

SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN ($1, $2) ORDER BY "posts"."updated_at" DESC

Passing an array to the where method causes the WHERE clause to use IN () rather than =. In the example above, I passed an array containing two items.

.limit(page_qty): This is where the pagination starts to happen, we tell the database that we only want 5 records at a time.

SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN ($1, $2) ORDER BY "posts"."updated_at" DESC LIMIT $3

As you probably realized, the $3 placeholder contains the number 5. If we stop here, the database would only send us the first 5 records. How do we tell the database to send us the next 5 records?

.offset(offset): This last method tells our database where to start. Remember, on line 3. offset = page_num * page_qty and page_qty always means 5, so let’s visualize some examples.

offset = 0 * 5 # page 0 - records 0 through 4.
offset = 1 * 5 # page 1 - records 5 through 9.
offset = 2 * 5 # page 2 - records 10 through 14.
etc.

so now we’ve simplified our so that our frontend just need to send the page number to communicate which ‘page’ of posts we want.

In the next blog post, I’ll show you how I crafted the frontend to a. know when the user scrolls to the bottom of the page, and b. send for the next ‘page’ of results.

--

--

Berel Levy

Experienced software engineer and data engineer who enjoys the finer things in coding.