DEV Community

loading...
Cover image for Better Rails Active Record Validation Messages

Better Rails Active Record Validation Messages

spidergears profile image Deepak Singh Updated on ・2 min read

Validations are used to ensure that only valid data is saved to database and no business rules are violated. For example, it may be important for business to ensure that users provides a valid email address and phone number. Model-level validations are the most common way (db-level constraints is another option) to achieve this. Model-level validations are database agnostic, simple to test and maintain. Rails makes this more fun with built-in helpers and support for custom validations.

All that being done, the next crucial step is to provide users with immediate feedback as they use your site. Rails allows to do just that with the :message option. It specifies the customised error message that will be added to the errors collection when the validation fails.

The :message option accepts a string or a proc.

  • When using strings, rails provides placeholder/interpolation variables to help add context and reduce cognitive load.
    • %{value}
    • %{attribute}
    • %{model} Use them in the message string as,
validates :age, numericality: { message: "%{attribute} must be a number" }

Age must be a number feels much better than must be a number.

  • Using procs adds more flexibility and logic to the message string. Proc has access to the object being validated and a data hash with keys model, attribute and value, same as the interpolation variable above.
validates :username,
    uniqueness: {
      message: ->(object, data) do
        "Hey #{object.name}!, #{data[:value]} is taken already!"
      end
    }
validates :score,
    presence: {
      message: ->(object, data) do
        if object.member?
          "something"
        else
          "Something else"
        end    
      end
    }

Magic does not end here, rails also allows overriding default validation messages via i18n-localization files.

en:
  activerecord:
    errors:
      models:
        user:
          attributes:
            firstname:
              blank: "custom message, can\'t be blank"

Presence validation error on firstname
Active Record provides couple of namespaces where message translations can be placed in order to provide different messages and translation for certain models, attributes, and/or validations. It also transparently takes single table inheritance into account.

Also placeholder/interpolation variables are still available.

en:
  activerecord:
    errors:
      models:
        user:
          attributes:
            firstname:
              blank: "Please fill in your %{attribute}"

http://guides.rubyonrails.org

Further, ActiveModel::Errors#full_messages prepends the attribute name to the error message using a separator that is looked up from errors.format (and defaults to %{attribute} %{message}). This too can be customised as

en:
  errors:
    # format to use in full error messages.
    format: "%{message} %{attribute}"

Discussion (0)

pic
Editor guide