I have the following validator:
# Source: http://guides.rubyonrails.org/active_record_validations_callbacks.html#custom-validators # app/validators/email_validator.rb class EmailValidator < ActiveModel::EachValidator def validate_each(object, attribute, value) unless value =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i object.errors[attribute] << (options[:message] || "is not formatted properly") end end end
I would like to be able to test this in RSpec inside of my lib directory. The problem so far is I am not sure how to initialize an EachValidator
.
Implementing the Validator Interface A Validator implementation must contain a constructor, a set of accessor methods for any attributes on the tag, and a validate method, which overrides the validate method of the Validator interface.
Custom validators take the value from the FormControl , where every input acts as a FormControl . So let's create a form along with a validator function. Create a new file called customvalidator. validator.
Use the CustomValidator control to provide a user-defined validation function for an input control. The CustomValidator control is a separate control from the input control it validates, which allows you to control where the validation message is displayed. Validation controls always perform validation on the server.
I am not a huge fan of the other approach because it ties the test too close to the implementation. Also, it's fairly hard to follow. This is the approach I ultimately use. Please keep in mind that this is a gross oversimplification of what my validator actually did... just wanted to demonstrate it more simply. There are definitely optimizations to be made
class OmniauthValidator < ActiveModel::Validator def validate(record) if !record.omniauth_provider.nil? && !%w(facebook github).include?(record.omniauth_provider) record.errors[:omniauth_provider] << 'Invalid omniauth provider' end end end
Associated Spec:
require 'spec_helper' class Validatable include ActiveModel::Validations validates_with OmniauthValidator attr_accessor :omniauth_provider end describe OmniauthValidator do subject { Validatable.new } context 'without provider' do it 'is valid' do expect(subject).to be_valid end end context 'with valid provider' do it 'is valid' do subject.stubs(omniauth_provider: 'facebook') expect(subject).to be_valid end end context 'with unused provider' do it 'is invalid' do subject.stubs(omniauth_provider: 'twitter') expect(subject).not_to be_valid expect(subject).to have(1).error_on(:omniauth_provider) end end end
Basically my approach is to create a fake object "Validatable" so that we can actually test the results on it rather than have expectations for each part of the implementation
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With