Custom validators based on ActiveModel::Validations, developed for Hydra applications.
- Ruby >= 1.9.3
- ActiveModel 4.x
ActiveFedora 7.x is a run-time dependency of the UniquenessValidator only, and is not provided by this gem.
Include in your Gemfile:
gem 'hydra-validations'
and
bundle install
- Metadata values are (often) arrays (XML or RDF).
- ActiveModel validators don't distinguish between array values and scalar values.
- We want validators that validate each member of an array value.
class Validatable
include ActiveModel::Validations
attr_accessor :type
validates_inclusion_of :type, in: %w(text image audio video)
end
>> record = Validatable.new
>> record.type = "text"
>> record.valid?
=> true
>> record.type = ["text", "image"]
>> record.valid?
=> false # not what we want :(
# now let's add Hydra::Validations ...
class CorrectlyValidatable
include ActiveModel::Validations
include Hydra::Validations
attr_accessor :type
validates_inclusion_of :type, in: %w(text image audio video)
end
>> record = CorrectlyValidatable.new
>> record.type = ["text", "image"]
>> record.valid?
=> true # Yay!
>> record.type = ["text", "newspaper"]
>> record.valid?
=> false
# tailors error message to specific invalid array value
>> puts record.errors.full_messages
Type value "newspaper" is not included in the list
class MyResource < ActiveTriples::Resource
# ActiveTriples::Resource includes ActiveModel::Validations
property :type, predicate: RDF::DC.type
validates_inclusion_of :type, in: %w(text image audio video)
end
>> resource = MyResource.new
>> resource.type = "text"
>> resource.valid?
=> false # Huh? Oh yeah, resource.type is actually an array ...
>> resource.type
=> ["text"]
class YourResource < ActiveTriples::Resource
include Hydra::Validations
property :type, predicate: RDF::DC.type
validates_inclusion_of :type, in: %w(text image audio video)
end
>> resource = YourResource.new
>> resource.type = "text"
=> "text"
>> resource.valid?
=> true # Yay!
>> resource.type << "newspapers"
>> resource.type
=> ["text", "newspapers"]
>> resource.valid?
=> false
>> puts resource.errors.full_messages
Type value "newspapers" is not included in the list
Hydra::Validations::EnumerableBehavior
is a mixin for an ActiveModel::EachValidator
that validates each member of an enumerable value. See the FormatValidator and InclusionValidator below for examples.
EnumerableBehavior overrides validate_each(record, attribute, value)
calling super(record, attribute, member)
for each member of an enumerable value (i.e., responds to :each
). The module "fixes" any error messages to include the specific member that failed validation -- for example, "is invalid"
becomes "value \"foo1\" is invalid"
, so the full message "Identifier is invalid"
becomes "Identifer value \"foo1\" is invalid"
.
allow_nil, allow_blank, and allow_empty
With EnumerableBehavior, validation of non-enumerables is unchanged (validate_each
simply returns super
); however, the validator options allow_nil
and allow_blank
apply only to the original value (the enumerable) and not to its members. For example, the value [""]
with the option allow_blank: true
will not bypass validation. As a result, empty enumerables will fail validation unless allow_blank
is true or the special enumerable option allow_empty
is true (that option does not bypass validation for non-enumerables that respond to :empty?
, e.g., empty strings).
See also the source code and spec tests.
Extends ActiveModel::Validations::FormatValidator
, adding EnumerableBehavior.
See ActiveModel::Validations::FormatValidator
for usage and options.
class FormatValidatable
include ActiveModel::Validations # required if not already included in class
include Hydra::Validations
attr_accessor :field
validates :field, format: { with: /\A[[:alpha:]]+\Z/ }
# ... or
# validates_format_of :field, with: /\A[[:alpha:]]+\Z/
end
>> record = FormatValidatable.new
=> #<FormatValidatable:0x007fe3cc0ece70>
>> record.field = "foo"
=> "foo"
>> record.valid?
=> true
>> record.field = ["foo"]
=> ["foo"]
>> record.valid?
=> true
>> record.field = ["foo", "bar"]
=> ["foo", "bar"]
>> record.valid?
=> true
>> record.field = ["foo1", "bar2"]
=> ["foo1", "bar2"]
>> record.valid?
=> false
>> puts record.errors.full_messages
Field value "foo1" is invalid
Field value "bar2" is invalid
Extends ActiveModel::Validations::InclusionValidator
, adding EnumerableBehavior.
See ActiveModel::Validations::InclusionValidator
for usage and options.
class InclusionValidatable
include ActiveModel::Validations # required if not already included in class
include Hydra::Validations
attr_accessor :field
validates :field, inclusion: { in: ["foo", "bar", "baz"] }
# or using helper method ...
# validates_inclusion_of :field, in: ["foo", "bar", "baz"]
end
>> record = InclusionValidatable.new
=> #<InclusionValidatable:0x007fe3cbc40098>
>> record.field = "foo"
=> "foo"
>> record.valid?
=> true
>> record.field = "foo1"
=> "foo1"
>> record.valid?
=> false
>> record.field = ["foo"]
=> ["foo"]
>> record.valid?
=> true
>> record.field = ["foo", "bar"]
=> ["foo", "bar"]
>> record.valid?
=> true
>> record.field = ["foo", "bar1", "baz"]
=> ["foo", "bar1", "baz"]
>> record.valid?
=> false
>> puts record.errors.full_messages
Field value "bar1" is not included in the list
Validates the uniqueness of an attribute based on a Solr index query.
Intended for ActiveFedora 7.x.
class UniquenessValidatable < ActiveFedora::Base
include Hydra::Validations # ActiveFedora::Base includes ActiveModel::Validations
has_metadata name: 'descMetadata', type: ActiveFedora::QualifiedDublinCoreDatastream
has_attributes :title, datastream: 'descMetadata', multiple: false
# Can use with multi-value attributes, but single cardinality is required.
has_attributes :source, datastream: 'descMetadata', multiple: true
validates :source, uniqueness: { solr_name: "source_ssim" }
# ... or using helper method
validates_uniqueness_of :title, solr_name: "title_ssi"
end
Validates the cardinality of the attribute value.
CardinalityValidator extends ActiveModel::Validations::LengthValidator
and
"tokenizes" values with Array.wrap(value)
. The "cardinality" of the value
is therefore the length the array. Accordingly,
nil
and empty enumerables have cardinality 0- scalar values (including empty string) have cardinality 1.
CardinalityValidator customizes the :wrong_length
, :too_short
and :too_long
messages
of LengthValidator to use language appropriate to cardinality. You can also override these
options.
class CardinalityValidatable
include ActiveModel::Validations # required if not already included in class
include Hydra::Validations
attr_accessor :field
validates :field, cardinality: { is: 1 }
# or with helper method ...
# validates_cardinality_of :field, is: 1
# or, for single cardinality (same as above) ...
# validates_single_cardinality_of :field
end
>> record = CardinalityValidatable.new
=> #<CardinalityValidatable:0x007fe3cbc632c8>
>> record.field = "foo"
=> "foo"
>> record.valid?
=> true
>> record.field = ["foo"]
=> ["foo"]
>> record.valid?
=> true
>> record.field = ["foo", "bar"]
=> ["foo", "bar"]
>> record.valid?
=> false
>> puts record.errors.full_messages
Field has the wrong cardinality (should have 1 value(s))