Testing a Custom Rails Model Validator
A SaaS application I am maintaining has been getting user registrations with donation descriptions with marketing URLs. As a quick fix for the issue I decided to write a custom validator to use in the modal. The idea was to make sure there wasn't a URL.
I did a Google search and the Stack Overflow answer that was right on top seemed to be out of date.
Here is how you can test a custom validator using RSpec, at least that is how I like to do it.
The validator:
# frozen_string_literal: true
# To assure the given input doesn't have any URLs
class UrlFreeValidator < ActiveModel::EachValidator
PATTERN = /(?:(?:https?|ftp|file):\/\/|www\.|ftp\.)(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[-A-Z0-9+&@#\/%=~_|$?!:,.])*(?:\([-A-Z0-9+&@#\/%=~_|$?!:,.]*\)|[A-Z0-9+&@#\/%=~_|$])/im
def validate_each(record, attribute, value)
return if (value =~ PATTERN).nil?
record.errors[attribute] << url_inclusion_error_message
end
def url_inclusion_error_message
options[:message] || "is not allowed to include an URL"
end
end
The test:
require "rails_helper"
module Test
class URLFreeValidatable
include ActiveModel::Model
include ActiveModel::Validations
attr_accessor :description
validates :description, url_free: true
end
end
RSpec.describe UrlFreeValidator do
it 'detects URL inclusion' do
validatable = Test::URLFreeValidatable.new(description: 'John https://www.google.com Doe')
expect(validatable.valid?).to be(false)
expect(validatable.errors[:description]).to eq(['is not allowed to include an URL'])
end
it 'passes if no URL is included' do
validatable = Test::URLFreeValidatable.new(description: 'John Doe')
expect(validatable.valid?).to be(true)
end
end
About the Author
Ziyan Junaideen -
Ziyan is an expert Ruby on Rails web developer with 8 years of experience specializing in SaaS applications. He spends his free time he writes blogs, drawing on his iPad, shoots photos.