will_paginate gem을 이용하는데, 다른 페이지에 같은 record가 올라오는 경우가 있었다. 문제는 infinite scrolling을 넣으며 ajax로 다음 페이지를 붙이다 보니, 중복되게 반복되는 경우가 발생했다. gem의 문제인가 해서 psql로 직접 sql을 날려보니, sql 결과에서도 같은 record가 나타났다.

Before

pnm_development=# SELECT  "sub_menus".*, "menus".name FROM "sub_menus" INNER JOIN "menus" ON "menus"."id" = "sub_menus"."menu_id" WHERE (menus.category_id = 1)  ORDER BY menus.name collate "C" asc LIMIT 10 OFFSET 10;

 id |    name    |         created_at         |         updated_at         | menu_id | description |        name         
----+------------+----------------------------+----------------------------+---------+-------------+---------------------
  6 | 물티슈     | 2016-08-10 14:12:25.575423 | 2016-08-10 14:12:25.575423 |       2 |             | 물티슈와 가제손수건
 49 | 바운서     | 2016-08-17 05:47:20.868362 | 2016-08-17 05:47:20.875056 |      16 |             | 바운서
 53 | 국산 분유  | 2016-08-29 06:54:39.305488 | 2016-08-29 06:54:39.315016 |      19 |             | 분유
 54 | 해외 분유  | 2016-08-29 06:54:54.123748 | 2016-08-29 06:54:54.130446 |      19 |             | 분유
 26 | 수유등     | 2016-08-10 14:12:25.698298 | 2016-08-10 14:12:25.698298 |       7 |             | 수유-모유
 23 | 수유패드   | 2016-08-10 14:12:25.681545 | 2016-08-10 14:12:25.681545 |       7 |             | 수유-모유
 22 | 수유브라   | 2016-08-10 14:12:25.677182 | 2016-08-10 14:12:25.677182 |       7 |             | 수유-모유
 21 | 수유복     | 2016-08-10 14:12:25.672055 | 2016-08-10 14:12:25.672055 |       7 |             | 수유-모유
 25 | 유두보호기 | 2016-08-10 14:12:25.694233 | 2016-08-10 14:12:25.694233 |       7 |             | 수유-모유
 20 | 수유쿠션   | 2016-08-10 14:12:25.668275 | 2016-08-10 14:12:25.668275 |       7 |             | 수유-모유
(10 rows)

pnm_development=# SELECT  "sub_menus".*, "menus".name FROM "sub_menus" INNER JOIN "menus" ON "menus"."id" = "sub_menus"."menu_id" WHERE (menus.category_id = 1)  ORDER BY menus.name collate "C" asc
 LIMIT 10 OFFSET 20;

 id |     name     |         created_at         |         updated_at         | menu_id | description |     name      
----+--------------+----------------------------+----------------------------+---------+-------------+---------------
 20 | 수유쿠션     | 2016-08-10 14:12:25.668275 | 2016-08-10 14:12:25.668275 |       7 |             | 수유-모유
 26 | 수유등       | 2016-08-10 14:12:25.698298 | 2016-08-10 14:12:25.698298 |       7 |             | 수유-모유
 19 | 유축기       | 2016-08-10 14:12:25.664174 | 2016-08-10 14:12:25.664174 |       7 |             | 수유-모유
 16 | 젖병소독기   | 2016-08-10 14:12:25.642145 | 2016-08-10 14:12:25.642145 |       6 |             | 수유-분유
 17 | 분유포트     | 2016-08-10 14:12:25.650437 | 2016-08-10 14:12:25.650437 |       6 |             | 수유-분유
 56 | 겉싸개       | 2016-08-29 13:41:40.355506 | 2016-08-29 13:41:40.363311 |      20 |             | 아기 의류
 55 | 속싸개       | 2016-08-29 13:41:29.740309 | 2016-08-29 13:41:29.748772 |      20 |             | 아기 의류
 33 | 기저귀정리함 | 2016-08-17 05:31:54.731063 | 2016-08-17 05:31:54.738381 |      12 |             | 아기가구
 34 | 아기수납장   | 2016-08-17 05:32:08.658293 | 2016-08-17 05:32:08.668742 |      12 |             | 아기가구
 39 | 힙시트       | 2016-08-17 05:33:23.976077 | 2016-08-17 05:33:23.983078 |      15 |             | 아기띠/힙시트
(10 rows)

문제가 되는 id 20번 record.

sql에서의 row 순서는 ORDER BY로 sort하지 않는 이상 정해져 있지 않다.stackoverflow 뭐가 나올지 알 수 없다는 말이네.

sub_menu에 대한 정렬을 추가해서 해결했다.

after

pnm_development=# SELECT  "sub_menus".*, "menus".name FROM "sub_menus" INNER JOIN "menus" ON "menus"."id" = "sub_menus"."menu_id" WHERE (menus.category_id = 1)  ORDER BY menus.name collate "C" asc, `sub_menus.name collate "C" asc LIMIT 10 OFFSET 10;

 id |    name    |         created_at         |         updated_at         | menu_id | description |        name         
----+------------+----------------------------+----------------------------+---------+-------------+---------------------
  6 | 물티슈     | 2016-08-10 14:12:25.575423 | 2016-08-10 14:12:25.575423 |       2 |             | 물티슈와 가제손수건
 49 | 바운서     | 2016-08-17 05:47:20.868362 | 2016-08-17 05:47:20.875056 |      16 |             | 바운서
 53 | 국산 분유  | 2016-08-29 06:54:39.305488 | 2016-08-29 06:54:39.315016 |      19 |             | 분유
 54 | 해외 분유  | 2016-08-29 06:54:54.123748 | 2016-08-29 06:54:54.130446 |      19 |             | 분유
 24 | 모유저장팩 | 2016-08-10 14:12:25.689986 | 2016-08-10 14:12:25.689986 |       7 |             | 수유-모유
 26 | 수유등     | 2016-08-10 14:12:25.698298 | 2016-08-10 14:12:25.698298 |       7 |             | 수유-모유
 21 | 수유복     | 2016-08-10 14:12:25.672055 | 2016-08-10 14:12:25.672055 |       7 |             | 수유-모유
 22 | 수유브라   | 2016-08-10 14:12:25.677182 | 2016-08-10 14:12:25.677182 |       7 |             | 수유-모유
 27 | 수유의자   | 2016-08-10 14:12:25.70253  | 2016-08-10 14:12:25.70253  |       7 |             | 수유-모유
 20 | 수유쿠션   | 2016-08-10 14:12:25.668275 | 2016-08-10 14:12:25.668275 |       7 |             | 수유-모유
(10 rows)

pnm_development=# SELECT  "sub_menus".*, "menus".name FROM "sub_menus" INNER JOIN "menus" ON "menus"."id" = "sub_menus"."menu_id" WHERE (menus.category_id = 1)  ORDER BY menus.name collate "C" asc, sub_menus.name collate "C" asc LIMIT 10 OFFSET 20;
 
 id |     name     |         created_at         |         updated_at         | menu_id | description |     name      
----+--------------+----------------------------+----------------------------+---------+-------------+---------------
 23 | 수유패드     | 2016-08-10 14:12:25.681545 | 2016-08-10 14:12:25.681545 |       7 |             | 수유-모유
 25 | 유두보호기   | 2016-08-10 14:12:25.694233 | 2016-08-10 14:12:25.694233 |       7 |             | 수유-모유
 19 | 유축기       | 2016-08-10 14:12:25.664174 | 2016-08-10 14:12:25.664174 |       7 |             | 수유-모유
 17 | 분유포트     | 2016-08-10 14:12:25.650437 | 2016-08-10 14:12:25.650437 |       6 |             | 수유-분유
 16 | 젖병소독기   | 2016-08-10 14:12:25.642145 | 2016-08-10 14:12:25.642145 |       6 |             | 수유-분유
 56 | 겉싸개       | 2016-08-29 13:41:40.355506 | 2016-08-29 13:41:40.363311 |      20 |             | 아기 의류
 55 | 속싸개       | 2016-08-29 13:41:29.740309 | 2016-08-29 13:41:29.748772 |      20 |             | 아기 의류
 33 | 기저귀정리함 | 2016-08-17 05:31:54.731063 | 2016-08-17 05:31:54.738381 |      12 |             | 아기가구
 34 | 아기수납장   | 2016-08-17 05:32:08.658293 | 2016-08-17 05:32:08.668742 |      12 |             | 아기가구
 38 | 아기띠       | 2016-08-17 05:33:14.93707  | 2016-08-17 05:33:14.942893 |      15 |             | 아기띠/힙시트
(10 rows)