Skip to content

Instantly share code, notes, and snippets.

@bf4
Created April 5, 2013 16:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bf4/5320847 to your computer and use it in GitHub Desktop.
Save bf4/5320847 to your computer and use it in GitHub Desktop.
Custom Rails Validatiorts
DateRange = Struct.new(:start_date, :end_date) do
def valid?
if start_date.to_s != '' && end_date.to_s != ''
start_date <= end_date
else
true
end
end
end
require File.expand_path '../../../lib/date_range', __FILE__
describe DateRange do
let(:start_date) { Date.civil(2013,1,2) }
let(:valid_end_date) { Date.civil(2013,1,3) }
let(:invalid_end_date) { Date.civil(2013,1,1) }
let(:valid_date_range) { DateRange.new(start_date, valid_end_date) }
context "is valid when" do
it "has a start_date" do
valid_date_range.start_date.should == start_date
end
it "has no start_date, but has an end_date" do
date_range = DateRange.new(nil,valid_end_date)
date_range.valid?
end
it "has an end_date" do
valid_date_range.end_date.should == valid_end_date
end
it "has no end_date" do
date_range = DateRange.new(start_date)
date_range.valid?
end
it "the start date is before the end date" do
valid_date_range.should be_valid
end
it "the start date is the same as the end date" do
valid_date_range.end_date = start_date
valid_date_range.should be_valid
end
end
context "is invalid when" do
it "has a start_date after the end_date" do
date_range = DateRange.new(start_date,invalid_end_date)
date_range.should_not be_valid
end
end
end
class DateRangeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
date_range = value
unless date_range.valid?
record.errors[attribute] << error_message(date_range)
end
end
private
def error_message(date_range)
"DateRange with start date #{date_range.start_date} and end date #{date_range.end_date} is invalid"
end
end
require 'addressable/uri'
#Accepts options[:message] and options[:allowed_protocols]
class UriValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
uri = parse_uri(value)
if !uri
record.errors[attribute] << generic_failure_message
elsif !allowed_protocols.include?(uri.scheme)
record.errors[attribute] << "must begin with #{allowed_protocols_humanized}"
end
end
private
def generic_failure_message
options[:message] || "is an invalid URL"
end
def allowed_protocols_humanized
allowed_protocols.to_sentence(:two_words_connector => 'or')
end
def allowed_protocols
@allowed_protocols ||= Array((options[:allowed_protocols] || ['http', 'https']))
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 'spec_helper'
# from https://gist.github.com/timocratic/5113293
describe UriValidator do
subject do
Test = Class.new do
include ActiveModel::Validations
attr_accessor :url
validates :url, uri: true
end
Test.new
end
it "should be valid for a valid http url" do
subject.url = 'http://www.google.com'
subject.valid?
subject.errors.full_messages.should == []
end
['http:/www.google.com','<>hi'].each do |invalid_url|
it "#{invalid_url.inspect} is an invalid url" do
subject.url = invalid_url
subject.valid?
subject.errors.should have_key(:url)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment