Blog

Thoughts from my daily grind

Testing a Custom Rails Model Validator

Posted by Ziyan Junaideen |Published: 28 June 2020 |Category: Code
Default Upload |

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
Tags
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.

Comments