lib/unique_within_region_validator.rb
#
# Validates that a record is unique within the region number
#
# Options:
# :match_case: Whether or not the uniqueness check should be case sensitive
# (default: true)
# :scope: An attribute used to further limit the scope of the uniqueness check
#
# Examples:
# validates :name, :unique_within_region => true
# validates :name, :unique_within_region => {:match_case => false}
# validates :name, :unique_within_region => {:scope => :dialog_type, :match_case => false}
#
class UniqueWithinRegionValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.nil? || !record.send(:"#{attribute}_changed?")
match_case = options.fetch(:match_case, true)
record_base_class = record.class.base_class.default_scoped
matches =
if match_case
record_base_class.where(attribute => value)
else
record_base_class.where(record_base_class.arel_table[attribute.to_sym].lower.eq(value.downcase))
end
matches = matches.where(options[:scope] => record.public_send(options[:scope])) if options.key?(:scope)
unless matches.in_region(record.region_id).where.not(:id => record.id).empty?
record.errors.add(attribute, "is not unique within region #{record.region_id}")
end
end
end