Generating error messages using ActiveModel::Errors
ActiveModel::Errors are widely used in ActiveRecord and therefore Rails, and while custom messages
can be provided to each validation using the
message key, it’s much more flexible to instead pass
a symbol as the message, which will cause the message to be looked up using the internationalisation
framework provided by the
i18n gem that is a dependency of Rails. Here are some examples:
validates :title, presence: true, message: "needs to be filled in" validates :title, presence: true # Will use built-in validation message look up validates :title, presence: true, message: :blank # ^ The same effect as the above validate do errors.add(:title, :contains_today_i_learned) unless title.includes?("TIL") end
Using an internationalised message is great for a number of reasons:
- It keeps strings out of your model
- It allows for custom error messages to be constrained to a single location
- (The obvious) - it allows error messages to be customized based on the current locale
Once these custom errors are built into your model, you may want to add a test to assert that the expected error messages are generated. You can assert against the string itself of course, however if you run your tests in multiple locales, or just want to keep validation message strings out of your model TEST as well as your model, the following method can come in handy.
When you run validations, an instance of
ActiveModel::Errors is available as the return value of
errors method on your model instance. This instance is normally used for accessing all the
validation errors on a model, but it also has a number of convenience functions - in particular, the
one we’re interested in is called
generate_message. This method accepts an attribute, and the
custom error (the symbol passed to the
message option of your validation, or a built-in validation
inclusion, etc., and returns the string form of the message. It will respect
the current setting of
I18n.locale when looking up error strings.
Here are some examples of looking up errors on a model (the instance of which is called
subject.errors.generate_message(:title, :blank) # => "can't be blank" subject.errors.generate_message(:title, :contains_today_i_learned) # => "must include the category 'TIL'" I18n.locale = "mi-NZ" subject.errors.generate_message(:title, :contains_today_i_learned) # => "me whakauru i te tuhinga 'TIL'"
For more information on the I18n translation format, and exactly how these above messages are resolved, see the I18n Rails Guide section on error message scopes.