Proposal for a new ActiveModel::Errors structure

There are few issues with the current ActiveModel::Errors class.

Firstly, when an error is added to ActiveModel::Errors class via #add method (https://github.com/rails/rails/blob/master/activemodel/lib/active_model/errors.rb#L294) its translation is added. It should not be translated when being added, but only when being read.

The second issue is a bit bigger. We’d like to create error responses in our API similar to GitHub:

   {
"message": "Validation Failed",
"errors": [
{
"resource": "Issue",
"field": "title",
"code": "missing_field"
}
]
}

Currently it’s impossible to figure out which validations actually failed for a given field, as AM::Errors provides only field name and translated error message. We’ve got a simple workaround for this issue:

module ActiveModel

class Errors

def error_types

@_error_types ||= Hash.new{|hash,k| hash[k] = []}

end

def add_with_save_names(attribute, message = nil, options = {})

message ||= :invalid

message = message.call if message.is_a?(Proc)

error_types[attribute] << message

add_without_save_names(attribute, message, options)

end

alias_method_chain :add, :save_names

end

end

This solution is far from perfect, but it's relatively simple and so far works for us.

The best solution would be to actually build a structure similar to GitHub response - from that structure it would be trivial to build #full_messages and similar methods and it would provide a lot of additional info which would be extremely useful for creating APIs.

Cheers,

Szymon

I would really love to see such changes in AM::Errors. +1 from me.

Seems good. Can you work on a patch and send a PR? If we can maintain
backwards compat, I am happy.

I’ll make all current methods to return the same result as they do now (even #to_json and similar methods) and use new structure only internally. The only question is how this new structure should be accessed via ActiveModel object - object.errors.errors? :slight_smile:

BTW. Aaron, if you have a while could you check PR about ActionDispatch::ParamsParser (https://github.com/rails/rails/pull/7444)?

Hey,

It’s been a while, but once again I’m working on an API-only Rails app and I have the same problem again :slight_smile:

Now that Rails 4.2 has been released and work on 5.0 has started, maybe it would be a good time to change ActiveModel::Errors API, so that it would allow to return translated error messages (like it does right now) or error codes (e.g. :invalid, :missing) that can be translated to any language by the app that’s using the API?

+1 for separation of concerns

+1

What do you think about using numbers for error codes? For example on ios side errors may have message (description) and code (among other things).

I don’t think numbers are a good idea in this case, as symbols map nicely to existing error codes in Rails (http://guides.rubyonrails.org/i18n.html#error-message-interpolation).

My friend just created a pull request that adds error codes to AM:Errors - https://github.com/rails/rails/pull/18322. It’s backward compatible, but methods like “<<”, “[]=” etc. don’t add errors to “codes” hash (however, they never actually did work correctly, as error messages added this way are not translated).

It might be possible to refactor AM::Errors completely and build “messages” based on “codes” instead of managing both of them.

Seems nice, +1 vote for that.

Finally, it was merged.
You can read about how to use it on https://cowbell-labs.com/2015-01-22-active-model-errors-details.html

W dniu czwartek, 8 stycznia 2015 16:59:37 UTC+1 użytkownik Tsyren napisał: