Have you ever used a custom validator class in Rails? I’m referring to a subclass of ActiveModel::Validator which you then include inside your model such as…
1 2 3 4 5 6 7
This allows you to define your validation methods in a custom class. It can be useful for extracting validation behavior out of your model. However, what you might not know is how this class is instantiated by Rails. I assumed that a new instance of my validator would be created each time validation was performed on an instance of the model during a web request. I also assumed that the validator instance would stick around if multiple validation attempts were made. Based on this assumption, I attempted to memoize the model instance inside my validator.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
This won’t work, and leads to some unexpected behavior. Everything seemed fine while submitting my form via the browser, but my tests were failing. Things that should have been valid weren’t, and vice versa. This eventually led me to do a little research on how Rails uses validators.
1 2 3 4 5 6 7 8 9 10 11
The moral of the story is that validates_with is a class method that creates a single instance of the validator when the model class is first loaded. If you memoize an instance variable inside the validator, it will not be replaced on successive calls to the validate method. In other words, the validator might be trying to validate the wrong object.
If you enjoyed this post, please consider subscribing.