So, this is what happened.
I was in the middle of some task and suddenly had to make a context switch to a different task that I had pushed earlier. I forgot to handle a failure case and the code went to production already. But the change was pretty simple.
I had to add a condition to some existing code that looked similar to this,
Consider this is the condition that I had to add.
With this done, I asked myself if I should test this out before pushing and the genius in me replied that this was a simple change and I could go ahead without any testing. I also had this pre-commit hook to save me from any syntax errors. So, I felt I was pretty much covered and good to go.
I pushed it, the pre-commit hook passed, shipped to prod as well 🚀 and I went back to my other task.
Within a few minutes, our error monitoring tool started showing even more errors, this time 100% of the requests were failing compared to the negligible 1% requests that were failing earlier.
Guessed what could have gone wrong already? Kudos to you.👏
If not, here's the error that will help you find it.
TypeError (class or module required)
If you think that
MyObject is not a class or module, you're wrong. Because that piece of code was already in production and is syntactical fine.
So what could have gone wrong? Give it a moment to look into it again.
Okay, here it goes, I didn't tell ruby explicitly about the execution precedence and as a result, it considered
MyObject && (self.some_validation? || self.other_validation?) as the argument to the method
So the result of
MyObject && (self.some_validation? || self.other_validation?)? is either one of these.
MyObject && true #true MyObject && false #false
As a result, the argument to
self.is_a? is now a boolean,
which throws the error, * TypeError (class or module required) *
The fix is pretty simple though, just add a bracket to let ruby know the precedence of the execution.
Days like these are bound to happen and it just makes you more humble and makes you learn the nuances of the language.