𝗪𝗵𝗮𝘁 𝗖𝗹𝗮𝘂𝗱𝗲 𝗧𝗵𝗼𝘂𝗴𝗵𝘁 𝗛𝗲 𝗞𝗻𝗲𝘄 𝗔𝗯𝗼𝘂𝘁 𝗥𝗮𝗶𝗹𝘀 𝗖𝗮𝗹𝗹𝗯𝗮𝗰𝗸𝘀

আমি LineItem রেকর্ড এবং তাদের S3 ফাইলগুলো ডিলিট করার জন্য একটি rake task চালানোর চেষ্টা করছিলাম। আমি Order-এর মতো parent model-গুলোতে থাকা ব্যয়বহুল (expensive) callbackগুলো এড়াতে চেয়েছিলাম।

আমি Claude-এর কাছে সাহায্য চেয়েছিলাম। এটি আমাকে খুব আত্মবিশ্বাসের সাথে একটি উত্তর দিয়েছিল। কিন্তু সেটি ভুল ছিল।

Rails, counter cache এবং কেন আপনাকে AI-এর পরামর্শ যাচাই করতে হবে, সে সম্পর্কে আমি যা শিখেছি তা নিচে দেওয়া হলো।

𝗧𝗵𝗲 𝗣𝗿𝗼𝗯𝗹𝗲𝗺 LineItem, OrderItem-এর অন্তর্ভুক্ত। OrderItem, Order-এর অন্তর্ভুক্ত। উভয় ক্ষেত্রেই counter_cache এবং touch ব্যবহার করা হয়েছে। একটি LineItem ডিলিট করলে একটি cascade ট্রিগার হয়। এই cascade-এর ফলে shipping estimation এবং total recalculation-এর মতো ভারী কাজগুলো (heavy jobs) শুরু হয়ে যায়। CPU এবং S3 খরচ কমাতে আমার এই cascade থামানো প্রয়োজন ছিল।

𝗧𝗵𝗲 𝗔𝗜 𝗠𝗶𝘀𝘁𝗮𝗸𝗲 Claude skip_callback ব্যবহার করার পরামর্শ দিয়েছিল। এটি একটি খারাপ ধারণা। skip_callback ক্লাসটিকে গ্লোবালি (globally) পরিবর্তন করে ফেলে। এটি আপনার অ্যাপের প্রতিটি thread-কে প্রভাবিত করে। যদি পুনরায় সক্রিয় করার আগেই আপনার কোড ক্র্যাশ করে, তবে আপনার callback গুলো চিরতরে বন্ধ হয়ে থাকবে।

এরপর আমি no_touching চেষ্টা করলাম। নিরাপদ থাকার জন্য আমি OrderItem এবং Order উভয় ক্ষেত্রেই কলটিকে wrap করেছিলাম। টেস্টগুলো পাস করলেও কনসোলে ভিন্ন কিছু দেখা গেল। Order-এর timestamp তখনও পরিবর্তিত হচ্ছিল।

𝗧𝗵𝗲 𝗥𝗲𝗮𝗹 𝗥𝗲𝗮𝘀𝗼𝗻 সমস্যাটি ছিল counter_cache কীভাবে touch-এর সাথে কাজ করে তা নিয়ে।

  • যখন আপনি counter_cache: true এবং touch: true একসাথে ব্যবহার করেন, Rails সেগুলোকে bundle করে ফেলে।
  • এটি একটি মাত্র raw SQL UPDATE ALL কমান্ড চালায়।
  • Raw SQL, ActiveRecord lifecycle-কে বাইপাস (bypass) করে।
  • যেহেতু এটি lifecycle বাইপাস করে, তাই after_commit hooks কাজ করে না।

এটি একটি অদ্ভুত প্যারাডক্স (paradox) তৈরি করেছিল:

  • raw SQL bundle-এর কারণে OrderItem callback গুলো কাজ করেনি।
  • Order callback গুলো কাজ করেছিল কারণ চেইনের পরবর্তী ধাপটি ছিল একটি সাধারণ touch।

𝗧𝗵𝗲 𝗙𝗶𝘅 আমার শুধু grandparent-কে no_touching-এর মধ্যে wrap করা প্রয়োজন ছিল।

Order.no_touching { line_item.destroy! }

এটি AR-level touch-কে Order model-এ পৌঁছাতে বাধা দেয়। এটি OrderItem-এর raw SQL থামায় না, তবে তাতে কিছু যায় আসে না কারণ counter cache bundle ইতিমধ্যেই সেই callback গুলোকে স্কিপ করে ফেলে।

𝗞𝗲𝘆 𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆𝘀

  • counter_cache: true + touch: true = raw SQL UPDATE ALL
  • Raw SQL সমস্ত after_commit hooks স্কিপ করে।
  • একটি সাধারণ touch (counter cache ছাড়া) স্ট্যান্ডার্ড AR lifecycle অনুসরণ করে এবং callback ট্রিগার করে।
  • AI কোডকে কখনো অন্ধভাবে বিশ্বাস করবেন না। Claude আপনাকে একটি উত্তর দিতে চায়, কিন্তু সেই উত্তরটি একটি hallucination কি না, তা নিয়ে সে মাথা ঘামায় না।

সবসময় 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