DataMapper models allow custom validations of two forms: those specific to a property, and overall object validations. For example:
# Validates the `name` property with the `check_name` method;
# any errors will be under `object.errors[:name]`
validates_with_method :name, method: :check_name
# Validates the object overall with the `overall_soundness` method;
# any errors will be under `object.errors[:overall_soundness]`
validates_with_method :overall_soundness
The second type makes sense for validations that involve multiple properties, but it also presents a problem: displaying errors to the user.
I'd like to display all errors that aren't attached to a particular property at the top of the form's page, but I don't see any easy way to list them.
How can I get a list of non-property-specific errors?
(I'm using DataMapper 1.2.0)
I'm hoping there's a more native way than this. I've added this method to my model:
# Validation errors not tied to a specific property. For instance,
# "end date must be on or before start date" (neither property is
# wrong individually, but the combination makes the model invalid)
# @return [Array] of error message strings
def general_validation_errors
general_errors = []
general_error_keys = errors.keys.reject do |error|
# Throw away any errors that match property names
self.send(:properties).map(&:name).include?(error) || error == :error
end
general_error_keys.each do |key|
general_errors << self.errors[key]
end
general_errors.flatten
end
At the top of a form, I can do this:
- if @my_model.general_validation_errors.any?
.errors
%ul
- @my_model.general_validation_errors.each do |error_message|
%li= error_message
Or, a monkey patch to Formtastic to allow f.general_validation_errors
would be:
# Let Formtastic forms use f.general_validation_errors to display these (if any)
module Formtastic
module Helpers
module ErrorsHelper
def general_validation_errors
unless @object.respond_to?(:general_validation_errors)
raise ArgumentError.new(
"#{@object.class} doesn't have a general_validation_errors method for Formtastic to call (did you include the module?)"
)
end
if @object.general_validation_errors.any?
template.content_tag(:div, class: 'errors') do
template.content_tag(:ul) do
content = ''
@object.general_validation_errors.each do |error|
content << template.content_tag(:li) do
error
end
end
content.html_safe
end
end
end
end
end
end
end
Model.validators.contexts[:default].select{|k|k.kind_of? DataMapper::Validations::MethodValidator}
ujifgc 2012-04-05 21:46
Model.validators.context[:default].select{|k| k.kind_of?(DataMapper::Validations::MethodValidator}
returns all the validations, not distinguishing between field-specific and otherwise. They each have a field_name
property, but 'general' validations don't have nil there; they have their own name. So that doesn't help me - Nathan Long 2012-04-09 16:00
For displaying... you could use flash?
Since you haven't tagged a language I'll just put the Ruby and Sinatra stuff and maybe you can find the DSL equivalent.
flash.now[:errors]
in your view with relevant conditional statements
and in route flash[:errors] = User.errors
special_overall_soundness
. The documentation forvalidates_with_method
encourages you to use it with one property/method at a time - ujifgc 2012-04-05 21:29