Як знову зробити Ruby on Rails Active Admin та великі таблиці PostgreSQL дружніми

pic

Якщо ви натрапили на цю статтю, то, ймовірно, ваш Active Admin вирішив трохи «зависнути», перш ніж показати просту сторінку індексу для однієї з ваших таблиць. Дозвольте здогадатися: це велика таблиця з сотнями тисяч записів. Але чому розмір таблиці має значення, якщо нам потрібно лише показати кілька перших рядків?

Здається, що розмір має значення не для Active Admin, а для самого PostgreSQL. Якщо бути точнішими — для підрахунку всіх рядків.

Передісторія: модель одночасного доступу (concurrency model) у PostgreSQL реалізована за допомогою техніки, яка називається MVCC (multiversion concurrency control), яка, щоб забезпечити коректність результатів у середовищах з паралельними запитами, змушує виконання такого простого запиту, як select count(*) from items; перевіряти всі рядки в таблиці items. І це не те, що можна вимкнути.

Active Admin показує загальну кількість рядків на кожній сторінці індексу, що робить продуктивність неприязною. Давайте виправимо це.

Найпростіше, що ми можемо зробити — це заборонити Active Admin викликати count для моделі:

index(pagination_total: false) do  
 # ...  
end

Це миттєво покращує продуктивність, але ви втратите можливість бачити будь-які підрахунки. Якщо це прийнятно — можете пропустити решту цієї статті і зафіксувати своє виправлення. Але якщо користувачам вашого застосунку потрібні числа (а інформація без чисел часто є безглуздою), вам доведеться копати глибше.

На щастя, PostgreSQL має спеціальну таблицю під назвою pg_class, де зберігаються метадані. Стовпець reltuples є особливо цікавим для нас, оскільки він зберігає оцінену кількість записів у таблицях. У нашій базі даних ця оцінка відрізняється від реальних значень не більше ніж на 2%, що абсолютно підходить для наших потреб.

Отже, давайте створимо невеликий concern, який можна включити до будь-якої моделі, щоб підтримати оцінену кількість:

Зверніть увагу на рядок номер 8: PostgreSQL повертає великі числа у науковому форматі, і «2.500000E+06» — це, ймовірно, не те, що ви хочете бачити в інтерфейсі.

Тепер нам потрібно показати це на сторінках індексу. Бічні панелі Active Admin рендеряться під списком фільтрів і здаються чудовим місцем для нашої мети. Створимо допоміжний метод, який можна використовувати на будь-якій сторінці індексу для додавання бічної панелі з кількістю:

У коді вище є кілька цікавих моментів. По-перше, параметр dsl (екземпляр ActiveAdmin::ResourceDSL) — це те, що ви маєте як self всередині методу ActiveAdmin.register. Він має метод sidebar, який (на диво) рендерить потрібну нам бічну панель. Параметр only: :index вказує, щоб не рендерити бічну панель на сторінці перегляду.

Тепер ми повинні використовувати метод estimated_count тільки для випадків, коли користувач не застосовує фільтри. В іншому випадку можна використовувати простий метод count, оскільки фільтрація все одно проходить через кожен рядок або використовує індекси. В обох випадках метод count не збільшить навантаження на продуктивність. Щоб дізнатися, чи застосовані фільтри, ми можемо перевірити параметр запиту q (який використовується гемом ransack під капотом Active Admin) — рядок номер 5. Все, що залишається, — це сформувати рядок і помістити його в елемент <span> у нашій бічній панелі.

Давайте викличемо допоміжний метод:

І ось як це виглядає:

pic

Ось і все. Але якщо ви перфекціоніст (або, як у моєму випадку, працюєте з дуже хорошою QA-командою), ви помітите, що кнопка «останній» у секції пагінації під таблицею на сторінках індексу більше не працює належним чином. Виходить, що без загальної кількості неможливо зрозуміти, скільки сторінок існує, і тому неможливо перейти до останньої. Ви можете придумати якісь «брудні» хаки, наприклад, змінити код гема kaminari, який використовується Active Admin для пагінації, але таким чином ви «підстрелите себе» швидше, ніж думаєте. Тому давайте просто сховаємо непотрібні кнопки в active_admin.scss:

.index.admin_items .pagination .last { display: none; }

Тепер ми завершили.

PS. Лайфхак: Час від часу запитуйте у користувачів вашого Active Admin, як часто вони використовують фільтри, і додавайте індекси до своїх таблиць.
У 21 столітті час значно дорожчий, ніж місце на жорсткому диску або використання процесора в хмарі.

Перекладено з: How to Make Ruby on Rails Active Admin and Large PostgreSQL Tables Friends Again