-
Notifications
You must be signed in to change notification settings - Fork 363
Validations: Decode response with format #441
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
Conversation
|
Can you break the changes to |
Sure! That change is required for this behavior to work, but I'm happy to open a smaller PR to merge it ahead of reviewing this one. |
Related to rails#441 This commit also adds the `remove_root = true` optional argument to the `JsonFormat` and `XmlFormat` modules' `#decode` method. The name and positional argument style draw direct inspiration from the `ActiveResource::Base#load` method's optional `remove_root = true` argument. The change is in support of replacing internal calls to `Hash.from_xml` and `ActiveSupport::JSON.decode`. Those method invocations are replaced with the appropriate format's `.decode` method.
|
Yeah, let's break in two. I intended to merge both, but I don't think that change on its own makes sense. |
|
I've opened #446. |
472ae3f to
71dd0cb
Compare
First, extract the `ActiveResource::ErrorsParser` class along with the
internal `ActiveResource::ActiveModelErrorsParser` class (that inherits
from `ActiveResource::ErrorsParser`). Configure a `errors_parser`
resource class attribute to control how errors are extracted from
decoded payloads.
The `errors_parser` pattern and the `ErrorsParser` class are directly
inspired by the `collection_parser` and `ActiveResource::Collection`
class.
ActiveResource::ErrorsParser
---
`ActiveResource::ErrorsParser` is a wrapper to handle parsing responses in
response to invalid requests that do not directly map to Active Model
error conventions.
You can define a custom class that inherits from
`ActiveResource::ErrorsParser` in order to to set the elements instance.
The initialize method will receive the `ActiveResource::Formats` parsed
result and should set `@messages`.
Consider a `POST /posts.json` request that results in a `422
Unprocessable Content` response with the following `application/json`
body:
```json
{
"error": true,
"messages": ["Something went wrong", "Title can't be blank"]
}
```
A Post class can be setup to handle it with:
```ruby
class Post < ActiveResource::Base
self.errors_parser = PostErrorsParser
end
```
A custom `ActiveResource::ErrorsParser` instance's `messages` method
should return a mapping of attribute names (or `"base"`) to arrays of
error message strings:
```ruby
class PostErrorsParser < ActiveResource::ErrorsParser
def initialize(parsed)
@messages = Hash.new { |hash, attr_name| hash[attr_name] = [] }
parsed["messages"].each do |message|
if message.starts_with?("Title")
@messages["title"] << message
else
@messages["base"] << message
end
end
end
end
```
When the `POST /posts.json` request is submitted by calling `save`, the
errors are parsed from the body and assigned to the Post instance's
`errors` object:
```ruby
post = Post.new(title: "")
post.save # => false
post.valid? # => false
post.errors.messages_for(:base) # => ["Something went wrong"]
post.errors.messages_for(:title) # => ["Title can't be blank"]
```
If the custom `ActiveResource::ErrorsParser` instance's `messages`
method returns an array of error message strings, Active Resource will
try to infer the attribute name based on the contents of the error
message string. If an error starts with a known attribute name, Active
Resource will add the message to that attribute's error messages. If a
known attribute name cannot be inferred, the error messages will be
added to the `:base` errors:
```ruby
class PostErrorsParser < ActiveResource::ErrorsParser
def initialize(parsed)
@messages = parsed["messages"]
end
end
```
Changes to ActiveResource::Formats::JsonFormat and ActiveResource::Formats::XmlFormat
---
This commit changes the `ActiveResource::Errors#from_xml` and
`ActiveResource::Errors#from_json` methods to be implemented in terms of
a new `#from_body` method. The `#from_body` method is flexible enough to
support any application-side custom formats, while internally flexible
enough to rely on the built-in JSON and XML formats.
71dd0cb to
09e0d7e
Compare
First, extract the
ActiveResource::ErrorsParserclass along with the internalActiveResource::ActiveModelErrorsParserclass (that inherits fromActiveResource::ErrorsParser). Configure aerrors_parserresource class attribute to control how errors are extracted from decoded payloads.The
errors_parserpattern and theErrorsParserclass are directly inspired by thecollection_parserandActiveResource::Collectionclass.ActiveResource::ErrorsParser
ActiveResource::ErrorsParseris a wrapper to handle parsing responses in response to invalid requests that do not directly map to Active Model error conventions.You can define a custom class that inherits from
ActiveResource::ErrorsParserin order to to set the elements instance.The initialize method will receive the
ActiveResource::Formatsparsed result and should set@messages.Consider a
POST /posts.jsonrequest that results in a422 Unprocessable Contentresponse with the followingapplication/jsonbody:{ "error": true, "messages": ["Something went wrong", "Title can't be blank"] }A Post class can be setup to handle it with:
A custom
ActiveResource::ErrorsParserinstance'smessagesmethod should return a mapping of attribute names (or"base") to arrays of error message strings:When the
POST /posts.jsonrequest is submitted by callingsave, the errors are parsed from the body and assigned to the Post instance'serrorsobject:If the custom
ActiveResource::ErrorsParserinstance'smessagesmethod returns an array of error message strings, Active Resource will try to infer the attribute name based on the contents of the error message string. If an error starts with a known attribute name, Active Resource will add the message to that attribute's error messages. If a known attribute name cannot be inferred, the error messages will be added to the:baseerrors:Changes to ActiveResource::Formats::JsonFormat and ActiveResource::Formats::XmlFormat
This commit changes the
ActiveResource::Errors#from_xmlandActiveResource::Errors#from_jsonmethods to be implemented in terms of a new#from_bodymethod. The#from_bodymethod is flexible enough to support any application-side custom formats, while internally flexible enough to rely on the built-in JSON and XML formats.