Що Claude вважав, що знає про Rails callbacks

Я намагався запустити rake task, щоб видалити записи LineItem та їхні файли в S3. Я хотів уникнути дорогих callback-ів на батьківських моделях, таких як Order.

Я звернувся по допомогу до Claude. Він надав мені впевнену відповідь. Він помилявся.

Ось що я дізнався про Rails, counter caches і чому ви повинні перевіряти поради ШІ.

Проблема LineItem належить до OrderItem. OrderItem належить до Order. Обидва використовують counter_cache та touch. Видалення LineItem запускає каскад. Цей каскад активує важкі завдання, такі як розрахунок вартості доставки та перерахунок загальної суми. Мені потрібно було зупинити цей каскад, щоб заощадити ресурси CPU та витрати на S3.

Помилка ШІ Claude запропонував використовувати skip_callback. Це погана ідея. skip_callback змінює клас глобально. Це впливає на кожен потік у вашому застосунку. Якщо ваш код аварійно завершиться до того, як ви знову його увімкнете, ваші callback-и залишаться вимкненими.

Потім я спробував no_touching. Щоб перестрахуватися, я обгорнув виклик і в OrderItem, і в Order. Тести пройшли, але консоль показала дещо інше. Часова мітка (timestamp) Order все одно змінювалася.

Справжня причина Проблема полягала в тому, як counter_cache працює з touch.

  • Коли ви використовуєте counter_cache: true та touch: true разом, Rails об'єднує їх.
  • Він виконує одну команду raw SQL UPDATE ALL.
  • Raw SQL оминає життєвий цикл ActiveRecord.
  • Оскільки він оминає життєвий цикл, хуки after_commit не спрацьовують.

Це створило дивний парадокс:

  • Callback-и OrderItem не спрацювали через об'єднання в raw SQL.
  • Callback-и Order СПРАЦЮВАЛИ, тому що наступний крок у ланцюжку був звичайним touch.

Виправлення Мені потрібно було обгорнути лише «дідуся» (grandparent) у no_touching.

Order.no_touching { line_item.destroy! }

Це не дає touch на рівні AR дійти до моделі Order. Це не зупиняє raw SQL на OrderItem, але це не має значення, оскільки bundle counter cache вже пропускає ці callback-и.

Ключові висновки

  • counter_cache: true + touch: true = raw SQL UPDATE ALL.
  • Raw SQL пропускає всі хуки after_commit.
  • Звичайний touch (без counter cache) слідує стандартному життєвому циклу AR і запускає callback-и.
  • Ніколи не довіряйте коду ШІ сліпо. Claude хоче дати вам відповідь. Йому байдуже, чи є ця відповідь галюцинацією.

Завжди перевіряйте свої припущення в Rails console. Навмисно «ламайте» код, щоб побачити, чи справді він зупиняє поведінку, яку ви хочете заблокувати.

Source: https://dev.to/husteadrobert/what-claude-thought-he-knew-about-rails-callbacks-and-how-console-testing-proved-him-wrong-j20

Optional learning community: https://t.me/GyaanSetuAi