-
Notifications
You must be signed in to change notification settings - Fork 0
/
proper_uniqueness_validation.rb
52 lines (42 loc) · 1.62 KB
/
proper_uniqueness_validation.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
module ProperUniquenessValidation
def self.included( base )
base.extend ClassMethods
end
def self.extract_index_name_from_exception( connection, exception )
case connection
when ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
extract_index_name_from_postgres_exception( exception )
else raise exception
end
end
def self.extract_index_name_from_postgres_exception( exception )
match = exception.original_exception.result.error_field( PGresult::PG_DIAG_MESSAGE_PRIMARY ).match(/"([^"]+)"/ )
match[1]
end
module ClassMethods
def uniqueness_error_attribute_for( index_name, attribute_name )
@_uniqueness_index_attribute_mapping ||= {}
@_uniqueness_index_attribute_mapping[index_name.to_sym] = attribute_name.to_sym
end
def _uniqueness_error_attribute_for( index_name )
@_uniqueness_index_attribute_mapping[index_name.to_sym]
end
end
private
def create_or_update
super
rescue ActiveRecord::RecordNotUnique,
PG::UniqueViolation => e
klass = self.class
raise unless klass.respond_to?( :connection )
index_name = ProperUniquenessValidation.extract_index_name_from_exception( klass.connection, e )
attribute = klass._uniqueness_error_attribute_for( index_name )
if !attribute
#TODO: Test this
logger.warn "Caught uniqueness exceptions but index '#{index_name}' was not registered\nAdd a \"uniqueness_error_attribute_for 'index_name', :error_attribute_name\"\nclause to your model '#{klass}'!"
raise
end
self.errors.add( attribute, :taken, :value => self.send( attribute ) )
return false
end
end