Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eprothro/5ea12fd2b0527baf0090 to your computer and use it in GitHub Desktop.
Save eprothro/5ea12fd2b0527baf0090 to your computer and use it in GitHub Desktop.

I love the concept and usability of an ActiveModel::Errors paradigm. However, I and others often find it frustrating to work with the implementation.

I'd love to see a proper ActiveModel::Error object, where the errors attribute of a model including ActiveModel::Errors was an Enumerator of these objects.

There are various implied benefits and added flexibility that could be introduced in a backwards compatible way later, and immedate benefits.

Immediate Benefits

The error type could be retained

APIs we build prefer to return Error objects to clients with the following schema:

{
  attribute:  "The model attribute to which the error applies. If blank, the error applies generically to the base model.",
  type:       "The type of error encountered with the model attribute or model."
  messsage:   "An internationalized message that can be displayed to a user.",
}

In particular, the type attribute allows clients to couple any logic they need on the error attribute and type, not the message, which should be able to change with business/product needs.

With a proper ActiveModel::Error object, this is easily done. With the current enumerable design, this is not a clean extension to make.

The error message can be lazily looked up

Currently, the message interpolation is looked up when the error is added to the model. This isn't necessarry, and is easily lazily evaluated when a derived attribute on an Error object.

Other Enhancements easily enabled

Accessing the attribute value more cleanly

error = model.errors.first
error.attribute
=> :username
error.attribute_value
=> 'eprothro'

Easier custom interpolation parameters

# en.yml
errors:
      models:
        user:
          attributes:
            username:
              taken: "%{value} has already been taken."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment