Вы будете удивлены - это не может работать!
Хорошо, причину можно найти в коде Rails. Первая проверка запускает код:
# Validations module
# Returns the Errors object that holds all information about
# attribute error messages.
def errors
@errors ||= Errors.new(self)
end
Поскольку это первый запуск, он создаст новый экземпляр класса Errors. Просто, не правда ли? Но есть недочёт - параметр self. В вашем случае это «контактный» объект.
Позже, когда вы снова вызовете это для клонированного объекта, экземпляр @errors больше не будет создан - так как он не равен нулю. И вот оно! Вместо прохождения «клонированного» «я» используется старое «я».
Позже в проверочном коде класс Errors запускает код, считывающий значение из @base, которое является self из инициализации. Видишь? Значения для теста читаются из оригинальной модели, а не из клона! Таким образом, проверка «клонированного» объекта выполняется на значениях из оригинала.
Хорошо, пока что «почему нет», а теперь несколько слов о «как».
Решение простое - просто установите @errors равным nil после клонирования и перед проверкой. Поскольку это довольно личное, простое назначение не работает. Но это работает:
cloned.instance_eval do
@errors = nil
end
И несколько советов для интересного чтения: http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/
Это довольно полное объяснение того, как работает валидация в Rails 3.