2019-05-03 06:17:27 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2013-05-23 12:52:12 +08:00
|
|
|
class UniqueAmongValidator < ActiveRecord::Validations::UniquenessValidator
|
|
|
|
def validate_each(record, attribute, value)
|
2021-04-21 17:36:32 +08:00
|
|
|
old_errors = []
|
|
|
|
record.errors.each do |error|
|
|
|
|
old_errors << error if error.attribute == attribute
|
|
|
|
end
|
2013-05-23 12:52:12 +08:00
|
|
|
|
|
|
|
# look for any duplicates at all
|
|
|
|
super
|
|
|
|
|
2021-04-21 17:36:32 +08:00
|
|
|
new_errors = []
|
|
|
|
record.errors.each do |error|
|
|
|
|
new_errors << error if error.attribute == attribute
|
|
|
|
end
|
2013-05-23 12:52:12 +08:00
|
|
|
|
|
|
|
# do nothing further unless there were some duplicates.
|
2021-04-21 17:36:32 +08:00
|
|
|
if new_errors.size - old_errors.size != 0
|
2013-05-23 12:52:12 +08:00
|
|
|
# now look only in the collection we care about.
|
2020-06-18 23:19:47 +08:00
|
|
|
dupes = options[:collection].call(record).where("lower(#{attribute}) = ?", value.downcase)
|
2013-05-23 12:52:12 +08:00
|
|
|
dupes = dupes.where("id != ?", record.id) if record.persisted?
|
|
|
|
|
|
|
|
# pop off the error, if it was a false positive
|
2021-04-21 17:36:32 +08:00
|
|
|
if !dupes.exists?
|
|
|
|
record.errors.delete(attribute)
|
|
|
|
old_errors.each do |error|
|
|
|
|
record.errors.add(
|
|
|
|
error.attribute,
|
|
|
|
error.type,
|
|
|
|
**error.options
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
2013-05-23 12:52:12 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|