Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?

I needed a URL validator - it needed to check that URL's had HTTP or HTTPS at the beginning. I initially wrote a "before save" action, but didn't like it cluttering up my model. I found a reference to basically "monkey patching" Rail's default Validator class, so that's what I did!

# concerns/url_validator.rb
require 'uri'

class UrlValidator < ActiveModel::Validator

  def validate(record)
    if record.url?
      uri = URI.parse(record.url)
      unless uri.kind_of?(URI::HTTP) || uri.kind_of?(URI::HTTPS)
        raise URI::InvalidURIError
        record.errors.add(:url, "is invalid: #{uri}")
      end
    end
  end
end
# spec/models/link_spec.rb

RSpec.describe Link do
  context "validations" do
    it { should validate_presence_of(:title)}
    it { should validate_presence_of(:url)}

    it "should not save invalid ULR" do
      title = "test url"
      invalid_url = "www.google"

      link = Link.new(title: title, url: invalid_url)
      expect {link.save}.to raise_error(URI::InvalidURIError)

    end

    it "should save valid URL" do
      title = "test url"
      valid_url = "http://google.com"

      Link.create!(title: title, url: valid_url)
      expect(Link.count).to eq(1)
    end
  end

  # more model tests here
# controllers/linkds_controller.rb

class LinksController < ApplicationController
  .
  .
  .
  def create
    link = current_user.links.create(link_params)
    # now checking only for "if link.save", instead of chained validations
    # refactored the following down
    # if link.valid_url? && link.save
    if link.save
      flash[:success] = "created new link"
      .
    .
  .
end
# models/link.rb
class Link < ActiveRecord::Base
  include ActiveModel::Validations
  validates_with UrlValidator

  validates :title, :url, presence: true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.