Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add response errors to ActiveModel using ActiveModel::Errors #178

Closed
wants to merge 2 commits into from

Conversation

lleger
Copy link

@lleger lleger commented Oct 7, 2013

What
This commit adds any response errors (such as those from calling save) to the ActiveModel::Error collection on the resource.

Why
Doing so enables accessing the errors hash via the errors attribute and allows the use of helper methods, such as full_messages. This also makes the Her::Model act more like an ActiveRecord object.

How
If the response errors are in an AR-like hash, then they're iterated over and added to the model via add on ActiveRecord::Error. For example:

# from remote model
{ errors => @user.errors }.to_json

# parsed in @response_errors
{ :errors => { :name => ["should not be blank"] } }

This PR includes passing tests and has been integrated into a production app. This was briefly discussed in #138.

Example

class User
  include Her::Model
  # validates :name, presence: true (on remote model)
end

@user = User.new
@user.save

@user.errors # => { :name => ["can't be blank"] }
@user.errors.any? # => true
@user.errors.full_messages # => ["Name can't be blank"]

This commit adds the private method `add_errors_to_base` to
`Her::Model::ORM`, which is called in `save` to add any response errors
to the resource's `ActiveModel::Error` collection. This means errors can
be accessed via `errors` on the object and helpers, such as
`full_messages` can be used.

*Example*
```
class User
  include Her::Model
  # validates :name, presence: true (on remote model)
end

@user = User.new
@user.save

@user.errors # => { :name => ["can't be blank"] }
@user.errors.any? # => true
@user.errors.full_messages # => ["Name can't be blank"]
```

- Adds private method to `Her::Model::ORM` to map response errors to an
  `ActiveModel::Error` object
- Adds call to method in `save` to add errors to resource object
- Adds spec to test error mapping
- Reformat error hashes in test responses
- Modify `Her::Errors::ResourceInvalid` to use errors object
@lleger
Copy link
Author

lleger commented Oct 7, 2013

Some of the tests randomly failed on 1.8.7. Fixed in 0f27448, so it looks like we're all green now.

@pencil
Copy link
Collaborator

pencil commented Oct 20, 2013

I'm not sure if we should mix the local validation messages with the remote validation messages... @remiprev, your thoughts on this one?

@remi
Copy link
Owner

remi commented Oct 20, 2013

I also think that we shouldn't mix local and remote errors.

Validations defined through ActiveModel::Validations go into #errors (like any ActiveModel-like object) and errors returned by the response go into #response_errors (this is the behavior added by Her).

@lleger
Copy link
Author

lleger commented Oct 30, 2013

I'm not sure I understand the dichotomy. If the error happens locally thanks to an ActiveModel validation on the Her model or remotely on the actual ActiveRecord resource, I still want to be able to display those errors in the same place and in the same way.

I don't think this does anything more than what Her is trying to do, it just enhances the functionality that's already there. I'm already getting the errors from the response, but now I get them in a nicely wrapped instance that's familiar and that I'm already interfacing with for the ActiveModel validations.

That being said, is there some version of this functionality that you would consider merging? For example, if instead of adding it to the base errors we transformed the response_errors hash into an ActiveModel::Error object, would that be agreeable?

I believe this is good functionality and I'm open to alternative implementations in order to see its way into the codebase.

@anicholson
Copy link

+1 to @lleger , I don't see the dichotomy either.

@pencil pencil reopened this Jan 20, 2014
@pencil
Copy link
Collaborator

pencil commented Jan 20, 2014

Guess you are right. But we can't be sure, that the errors from the server are always a Hash. What if they are just a simple Array. Or even worse: A String?

@lleger
Copy link
Author

lleger commented Jan 20, 2014

We perhaps could ignore any ill-formatted errors, but as a matter of convention I'd imagine, if you're sending the errors back over the wire, then it'd make sense to send them back as a hash (otherwise there'd be no relation between the error message and the attribute).

@pencil
Copy link
Collaborator

pencil commented Jan 21, 2014

I'm sorry, but it doesn't work that way. We can not rely on something because "it would make sense". her is designed to work with as many APIs as possible and we can therefore not enforce such strong policies.

@lleger
Copy link
Author

lleger commented Jan 21, 2014

I'm struggling to consider a way to implement this if the response errors aren't formatted as a hash. It would be difficult to relate an error message to an attribute if we get an array or a string. Do you have any recommendations?

It currently works fine with how Rails and AR serialize a failed validation back to JSON, but that's the only API I've tested it with.

@lleger
Copy link
Author

lleger commented Feb 18, 2014

We've had some lively discussion on this, and I'd like to see it get merged in, so I'm pinging y'all back to see if there's some manner we can get this functionality into Her.

@pencil
Copy link
Collaborator

pencil commented Feb 19, 2014

The suggested solution is only compatible with how Rails encodes the errors. Other APIs may use other formats and I can't think of an easy way to tackle this without having a confusing programming API.

As initially mentioned by me and @remiprev, mixing local and remote validation messages will open Pandora's box. Not only because of the issues we discussed so far. It would probably also be quite confusing for the programmers.

I think using custom code to handle this in your application as needed is the right approach.

@pencil pencil closed this Feb 19, 2014
@lleger
Copy link
Author

lleger commented Feb 19, 2014

Unfortunate—was really hoping we could get this merged. It's a splendid addition for our usage. In case anyone finds a similar need, we'll keep our fork maintained.

@noctivityinc
Copy link

@lleger I know this is an old issue but I completely agree with you. Id like to try to integrate the same logic using a callback but unfortunately the callback is cancelled if an error occurs. How did you eventually handle this?

@lleger
Copy link
Author

lleger commented Oct 19, 2018

@noctivityinc To be honest, this is quite old. We abandoned Her not long after this in favor of greener pastures. Our fork has the code we ended up using, though, and you're free to use it if it's helpful. Good luck!

@noctivityinc
Copy link

noctivityinc commented Oct 19, 2018 via email

@lleger
Copy link
Author

lleger commented Oct 19, 2018

We ended up rewriting the app in question to use a React frontend that just straight consumed a Rails API. Much better experience than trying to consume an API on the backend and push back a response.

@noctivityinc
Copy link

noctivityinc commented Oct 19, 2018 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants