Devise, an authentication solution for Rails, gives some modules that add some cool functionalities to the models, one of them is Validatable which adds the validations needed for emails and passwords. One of those validations is validates_uniqueness_of which is in charge of checking that the email address is unique.
I have been working on a Rails API since 2016 and it uses Devise; users are required to give unique emails. But something change: now the API supports a Chatbox which will be added on many websites, we want to get those visitors and we have to support duplicate emails.
The best approach is to make a new model for those users, but because of the impact to the application (which is a chat application) we don’t have the time to make it happen.
Another alternative may be this Validatable should allow email uniqueness to be scoped#4767 but the discussion is still open. Maybe removing the Validatable module and implement everything but it will generate extra work and will increase the probability of failures (remember always TDD). Instead of that I followed a different approach.
Taking advantage from Ruby, I get the model validators for the email attribute and I find the UniquenessValidator. Then I redefine the validate method of the validator.
At a Rails model:
This is called Monkey Patch. It is a vague term, the best definition is dynamic modification of a class on runtime , and in this case specifically it is redefining an instance method on runtime. Here are some good explanations at this StackOverflow thread, and citing Patrick Ewing:
Well, I was just totally sold by Adam, the idea being that if it walks like a duck and talks like a duck, it’s a duck, right? So if this duck is not giving you the noise that you want, you’ve got to just punch that duck until it returns what you expect.
Kind of cool but something you want to avoid. Personally I believe that a good design will avoid these kind of things. But for those hard moments or for well designed solutions keep this in mind.
Good material for reading:
Redefining Instance Methods at Runtime by Jeremy Friesen
Understanding Ruby Singleton Classes by Peter J. Jones
3 Ways to Monkey-Patch Without Making a Mess by Justin Weiss
Refinements at Ruby Docs