Rails displays all validation error messages associated with a given field. If I have three validates_XXXXX_of :email
, and I leave the field blank, I get three messages in the error list.
Example:
validates_presence_of :name validates_presence_of :email validates_presence_of :text validates_length_of :name, :in => 6..30 validates_length_of :email, :in => 4..40 validates_length_of :text, :in => 4..200 validates_format_of :email, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i<br/>
<%= error_messages_for :comment %>
gives me:
7 errors prohibited this comment from being saved There were problems with the following fields: Name can't be blank Name is too short (minimum is 6 characters) Email can't be blank Email is too short (minimum is 4 characters) Email is invalid Text can't be blank Text is too short (minimum is 4 characters)
It is better to display one messages at a time. Is there an easy way to fix this problem? It looks straightforward to have a condition like: If you found an error for :email
, stop validating :email
and skip to the other field.
[Update] Jan/2013 to Rails 3.2.x - update syntax; add spec
Inspired by new validation methods in Rails 3.0 I'm adding this tiny Validator. I call it ReduceValidator
.
lib/reduce_validator.rb
:
# show only one error message per field # class ReduceValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) return until record.errors.messages.has_key?(attribute) record.errors[attribute].slice!(-1) until record.errors[attribute].size <= 1 end end
My Model looking like - notice the :reduce => true
:
validates :title, :presence => true, :inclusion => { :in => %w[ Mr Mrs ] }, :reduce => true validates :firstname, :presence => true, :length => { :within => 2..50 }, :format => { :without => /^\D{1}[.]/i }, :reduce => true validates :lastname, :presence => true, :length => { :within => 2..50 }, :format => { :without => /^\D{1}[.]/i }, :reduce => true
Works like a charm in my current Rails Project. The advantageous is, i've put the validator only on a few fields not all.
spec/lib/reduce_validator_spec.rb
:
require 'spec_helper' describe ReduceValidator do let(:reduce_validator) { ReduceValidator.new({ :attributes => {} }) } let(:item) { mock_model("Item") } subject { item } before(:each) do item.errors.add(:name, "message one") item.errors.add(:name, "message two") end it { should have(2).error_on(:name) } it "should reduce error messages" do reduce_validator.validate_each(item, :name, '') should have(1).error_on(:name) end end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With