I've been trying to follow Bryan Helmkamp's 7 Patterns to Refactor Fat ActiveRecord Models, working my way to writing better code.
One of the things I liked – and recently tried to implement – where specialized Form Objects. These objects handle everything (validation, saving, etc) related to a specific (large'ish) form.
One thing he left out, was how to handle uniqueness constraints often required for form validations (and unavailable outside of
ActiveRecord based classes). Here's my take on overwriting the default
UniquenessValidator to handle such cases:
class UniquenessValidator < ActiveRecord::Validations::UniquenessValidator
@klass = options[:model] if options[:model]
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]
# 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.
record_org, attribute_org = record, attribute
attribute = options[:attribute].to_sym if options[:attribute]
record = options[:model].new(attribute => value)
options.except(:case_sensitive, :scope).merge(value: value))
Now you can use this specific validator along all the others provided by ActiveModel as long as you include