require 'active_support/core_ext/array/wrap' module Hydra module Validations # # UniquenessValidator - an ActiveFedora model validator # # Usage: # # validates :field, uniqueness: { solr_name: "field_ssim" } # validates_uniqueness_of :field, solr_name: "field_ssim" # # Restrictions: # # - Accepts only one attribute (can have more than one UniquenessValidator on a model, however) # - :solr_name option must be present # - Can be used on enumerable values (attribute defined with :multiple=>true option), but # validator also validates single cardinality, so will not pass validation if enumerable # has more than one member. # # CAVEAT: The determination of uniqueness depends on a Solr query. # False negatives (record invalid) may result if, for example, # querying a Solr field of type "text". # class UniquenessValidator < ActiveModel::EachValidator def check_validity! if attributes.length > 1 raise ArgumentError, "UniquenessValidator accepts only a single attribute: #{attributes}" end unless options[:solr_name].present? raise ArgumentError, "UniquenessValidator requires the :solr_name option be present." end end def validate_each(record, attribute, value) wrapped_value = Array.wrap(value) if wrapped_value.length > 1 record.errors.add(attribute, "can't have more than one value") elsif wrapped_value.empty? record.errors.add(attribute, "can't be empty") unless options[:allow_empty] else conditions = {options[:solr_name] => wrapped_value.first} conditions.merge!("-id" => record.id) if record.persisted? record.errors.add attribute, "has already been taken" if record.class.exists?(conditions) end end end module HelperMethods def validates_uniqueness_of *attr_names validates_with UniquenessValidator, _merge_attributes(attr_names) end end end end