Quick Tip: Test Custom ActiveRecord Validators

I’ve always found writing and testing custom ActiveRecord validations to be a straightforward process. In your model, add a private validation method and hook in to the validation callbacks using the validate class method. In your tests, build a model with invalid data, and assert its validity (or lack thereof).

But more and more, I find myself writing validations that I’d like to share between models. The Active Record Validations and Callbacks Rails Guide (and the Rails API docs) suggest that the best way to create a reusable validation for individual attributes is by creating a subclass of ActiveModel::EachValidator. This even integrates with the Rails 3 ActiveModel validates method for easy-to read validations. Cool stuff.

But what do you do when you want to test these validators in isolation from the business logic of your models? Here’s a pretty sweet solution I found, using Rspec and the with_model gem.

In this example, I’ve written an excitement validator. A string attribute will pass validation if it ends with an exclamation point, and fail if it does not. Here’s my ActiveModel::EachValidator subclass:

And, using with_model, here’s my spec:

I placed these files in app/validations and spec/validations, respectively – Rails 3 and higher will include any directories in app/ on your load path automatically.

An alternative way of testing the validation would be to instantiate the ExcitementValidator class directly and test the results of the validate_each method. I like this with_model approach, however, because it tests both the validation code itself and that the class complies with ActiveModel::EachValidator’s interface.