Skip to content

Instantly share code, notes, and snippets.

@adamico
Forked from johnjohndoe/uri_validator.rb
Last active June 21, 2017 05:46
Show Gist options
  • Save adamico/2a781d6a4fc2ff577e7f to your computer and use it in GitHub Desktop.
Save adamico/2a781d6a4fc2ff577e7f to your computer and use it in GitHub Desktop.
Rails 4 with I18n working interpolations
en:
errors: &errors
messages:
bad_uri: is an invalid url
bad_protocol: must start with %{protocols}
activemodel:
errors:
<<: *errors
activerecord:
errors:
<<: *errors
require 'addressable/uri'
# Source: http://gist.github.com/bf4/5320847
# Accepts options[:allowed_protocols]
# To make the error message work you must add :bad_uri and :bad_protocol keys to your locale file (see example locale file)
# app/validators/uri_validator.rb
class UriValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
uri = parse_uri(value)
if !uri
record.errors.add(attribute, :bad_uri, options)
elsif !allowed_protocols.include?(uri.scheme)
record.errors.add(attribute, :bad_protocol, protocols: allowed_protocols_humanized)
end
end
private
def allowed_protocols_humanized
allowed_protocols.to_sentence(:two_words_connector => ' / ')
end
def allowed_protocols
@allowed_protocols ||= [(options[:allowed_protocols] || ['http', 'https'])].flatten
end
def parse_uri(value)
uri = Addressable::URI.parse(value)
uri.scheme && uri.host && uri
rescue URI::InvalidURIError, Addressable::URI::InvalidURIError, TypeError
end
end
require 'rails_helper'
# Source: http://gist.github.com/bf4/5320847
# spec/validators/uri_validator_spec.rb
class Foo
include ActiveModel::Validations
attr_accessor :url
validates :url, uri: true
end
describe UriValidator do
subject { Foo.new }
it 'should be valid for a valid http url' do
subject.url = 'http://www.google.com'
expect(subject).to be_valid
expect(subject.errors.full_messages).to be_empty
end
['http:/www.google.com', '<>hi',
'www.google.com', 'google.com'].each do |invalid_url|
it "#{invalid_url.inspect} is an invalid url" do
subject.url = invalid_url
expect(subject).not_to be_valid
expect(subject.errors).to have_key(:url)
expect(subject.errors[:url]).to(
include(I18n.t(:bad_uri, scope: 'activemodel.errors.messages'))
)
end
end
['ftp://ftp.google.com', 'ssh://google.com'].each do |invalid_url|
it "#{invalid_url.inspect} does not respect the allowed protocols" do
subject.url = invalid_url
expect(subject).not_to be_valid
expect(subject.errors).to have_key(:url)
expect(subject.errors[:url]).to(
include(I18n.t(:bad_protocol,
scope: 'activemodel.errors.messages',
protocols: 'http / https'))
)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment