کلاڈ (Claude) نے ریلز (Rails) کال بیکس (callbacks) کے بارے میں کیا سمجھا
میں نے LineItem ریکارڈز اور ان کی S3 فائلوں کو حذف کرنے کے لیے ایک rake task چلانے کی کوشش کی۔ میں Order جیسے پیرنٹ ماڈلز (parent models) پر مہنگے کال بیکس (callbacks) سے بچنا چاہتا تھا۔
میں نے مدد کے لیے Claude سے پوچھا۔ اس نے مجھے ایک پراعتماد جواب دیا۔ وہ غلط تھا۔
یہاں وہ سب کچھ ہے جو میں نے Rails، counter caches، اور اس بارے میں سیکھا کہ آپ کو AI کے مشورے کی تصدیق کیوں کرنی چاہیے۔
مسئلہ LineItem، OrderItem سے تعلق رکھتا ہے۔ OrderItem، Order سے تعلق رکھتا ہے۔ دونوں counter_cache اور touch کا استعمال کرتے ہیں۔ LineItem کو حذف کرنے سے ایک سلسلہ (cascade) شروع ہو جاتا ہے۔ یہ سلسلہ شپنگ کے تخمینوں (shipping estimations) اور کل ری کیلکولیشنز (total recalculations) جیسے بھاری کاموں (heavy jobs) کو متحرک کر دیتا ہے۔ مجھے CPU اور S3 کے اخراجات بچانے کے لیے اس سلسلے کو روکنے کی ضرورت تھی۔
AI کی غلطی Claude نے skip_callback استعمال کرنے کا مشورہ دیا۔ یہ ایک برا خیال ہے۔ skip_callback کلاس کو عالمی سطح (globally) پر تبدیل کر دیتا ہے۔ یہ آپ کی ایپ کے ہر تھریڈ (thread) کو متاثر کرتا ہے۔ اگر آپ کے کوڈ کے دوبارہ فعال ہونے سے پہلے کریش ہو جائے، تو آپ کے کال بیکس ہمیشہ کے لیے ختم ہو جائیں گے۔
پھر میں نے no_touching آزمایا۔ میں نے احتیاط کے طور سے OrderItem اور Order دونوں میں کال کو لپیٹا (wrapped)۔ ٹیسٹ پاس ہو گئے، لیکن کنسول نے کچھ اور ہی دکھایا۔ Order کا ٹائم اسٹیمپ (timestamp) اب بھی تبدیل ہو رہا تھا۔
اصل وجہ مسئلہ یہ تھا کہ counter_cache، touch کے ساتھ کیسے کام کرتا ہے۔
- جب آپ counter_cache: true اور touch: true کو ایک ساتھ استعمال کرتے ہیں، تو Rails انہیں یکجا (bundle) کر دیتا ہے۔
- یہ ایک ہی raw SQL UPDATE ALL کمانڈ چلاتا ہے۔
- Raw SQL، ActiveRecord لائف سائیکل (lifecycle) کو نظر انداز کر دیتا ہے۔
- چونکہ یہ لائف سائیکل کو نظر انداز کر دیتا ہے، اس لیے after_commit ہکس (hooks) متحرک نہیں ہوتے۔
اس سے ایک عجیب تضاد (paradox) پیدا ہوا:
- raw SQL بنڈل کی وجہ سے OrderItem کال بیکس متحرک نہیں ہوئے۔
- Order کال بیکس متحرک ہوئے کیونکہ زنجیر میں اگلا مرحلہ ایک سادہ touch تھا۔
حل مجھے صرف grandparent ماڈل کو no_touching میں لپیٹنے کی ضرورت تھی۔
Order.no_touching { line_item.destroy! }
یہ AR-level touch کو Order ماڈل تک پہنچنے سے روک دیتا ہے۔ یہ