validações de exclusividade em ActiveModel

Tenho tentado seguir os 7 padrões de Bryan Helmkamp para refatorar modelos de gordura ActiveRecord , trabalhando para escrever um código melhor.

Uma das coisas que gostei – e recentemente tentei implementar – era objetos de formulário especializados . Esses objetos tratam de tudo (validação, salvamento, etc.) relacionado a um formulário específico (grande).

Uma coisa que ele deixou de fora foi como lidar com as restrições de exclusividade frequentemente exigidas para validações de formulário (e indisponíveis fora das ActiveRecordclasses baseadas). Esta é minha opinião sobre a substituição do padrão UniquenessValidatorpara lidar com esses casos:

class UniquenessValidator < ActiveRecord::Validations::UniquenessValidator
def setup(klass)
super
@klass = options[:model] if options[:model]
end

def validate_each(record, attribute, value)
# UniquenessValidator can't be used outside of ActiveRecord instances, here
# we return the exact same error, unless the 'model' option is given.
#
if ! options[:model] && ! record.class.ancestors.include?(ActiveRecord::Base)
raise ArgumentError, "Unknown validator: 'UniquenessValidator'"

# If we're inside an ActiveRecord class, and `model` isn't set, use the
# default behaviour of the validator.
#
elsif ! options[:model]
super

# Custom validator options. The validator can be called in any class, as
# long as it includes `ActiveModel::Validations`. You can tell the validator
# which ActiveRecord based class to check against, using the `model`
# option. Also, if you are using a different attribute name, you can set the
# correct one for the ActiveRecord class using the `attribute` option.
#
else
record_org
, attribute_org = record, attribute

attribute
= options[:attribute].to_sym if options[:attribute]
record
= options[:model].new(attribute => value)

super

if record.errors.any?
record_org
.errors.add(attribute_org, :taken,
options
.except(:case_sensitive, :scope).merge(value: value))
end
end
end
end

Agora você pode usar este validador específico junto com todos os outros fornecidos pelo ActiveModel , desde que você inclua ActiveModel::Validations.