Rails: how to show only one validation error message per attribute

Steffen Boller
2 min readAug 7, 2016

--

The problem

Quite often you will have a lot of different validations for each attribute of your model, e.g. your User model validation vor email could look like this:

validates :email, presence: true, format: /\A[^@]+@[^@]+\z/

When you are now validating a form and a users does not enter any email, he will see 2 validation error messages for the email attribute

  • Email can’t be blank
  • Email is invalid

Thats not nice and can even get worse with more and more validations you define per attribute. What you want is only to show one message per attribute to your customer.

The solution

A lot of different approaches are discussed on Stack Overflow: Rails validation error messages: Displaying only one error message per field.

I am not a fan of changing the validation methods or somehow to restrictions in your model. As you will always have some kind of errors_helper.rb to display your messages (because you want to do some some HTML stuff there with nice alert colors) thats the place to go.

Lets assume you use devise as many people do, than you got a devise_helper.rb (or add one manually for editing):

def devise_error_messages!
messages = resource.errors.full_messages.map { |msg| content_tag(:li, msg) }.join
...
end

which will lead to the above shown multiple messages per attribute (due to errors.full_messages).

We can simply adjust this to:

messages = resource.errors.details.keys.map { |attr|      content_tag(:li, resource.errors.full_messages_for(attr).first) }.join

Thanks to errors.full_messages_for().first we can iterate through all attributes and just output the first error message. See rails documentation for more information.

You could also iterate trough using resource.errors.messages.keys.

Rails 5 note: errors.details[:attribute] seems only to be present with Rails 5— if you use earlier versions you can add the gem ActiveModel::Errors#details to use with Rails 3.2.x and 4.x apps.

Additional information on how to use errors.details[:attribute] here.

By the way: No need of defining something like “#{attr} #{msg}” in your helper — to adjust the way each full message is shown I would always recommend putting this in your yml language files:

en:
errors:
format: “%{attribute} %{message}”

--

--

Steffen Boller

I like fintech, ruby on rails & watches. I share spotted rails gems and how to use them + my approaches on best practice for common challenges.