This article was written before Drivy was acquired by Getaround , and became Getaround EU. Some references to Drivy may therefore remain in the post

At Drivy, we use the Virtus gem to build form objects in our codebase. This lets us:

Keep our business logic out of the Controller and Views

Deal with unpersisted attributes

Add specific validations instead of adding them directly in the model

Display custom data validations errors directly in the form

Use features from ActiveModel::Model by including it

Sometimes, we have to sanitize user input: format the data, remove whitespaces and so on. Here is a convenient way to handle it with Virtus.

Using #coerce

Let’s imagine that we want to remove all the whitespaces from a VAT number recorded as a string. This is a pretty simple use case, but concepts will apply to more complex situation as well.

First we have to define a custom attribute object for the attribute we want to sanitize. It has to inherit from Virtus::Attribute in order to use the coerce method. Then, in this method, we just have to define the reformatting we want to perform.

class SanitizedVatNumber < Virtus :: Attribute def coerce ( value ) value . respond_to? ( :to_s ) ? value . to_s . gsub ( /\s+/ , '' ) : value end end

Next, in your Virtus form object, we specify the vat_number attribute - the one we want to update - as a SanitizedVatNumber :

class CompanyForm attribute :vat_number , SanitizedVatNumber def initialize (. . . ) end end

And there we have it! The vat_number will be sanitized once the form is submitted.

Testing it with Rspec

It is also easy to add basic tests on this custom Virtus attribute, for instance by using Rspec:

describe SanitizedVatNumber do let ( :object ) { described_class . build ( described_class ) } subject { object . coerce ( value ) } context 'when vat_number is nil' do let ( :value ) { nil } it { is_expected . to eq ( '' ) } end context 'when vat_number has white spaces' do let ( :value ) { 'EN XX 999 999 999' } it { is_expected . to eq ( 'ENXX999999999' )} end end

Conclusion

You avoid giving too much responsibility to your form object, which would be the risk of sanitizing attributes directly inside the form. Plus, Virtus custom coercion can be reused across multiple forms, and lends itself well to be easily unit tested.