mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add support for errors in JSON format.
[#1956 state:committed] Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
This commit is contained in:
parent
793a9f122f
commit
797588543e
4 changed files with 83 additions and 26 deletions
|
@ -1,5 +1,7 @@
|
|||
*Edge*
|
||||
|
||||
* Add support for errors in JSON format. #1956 [Fabien Jakimowicz]
|
||||
|
||||
* Recognizes 410 as Resource Gone. #2316 [Jordan Brough, Jatinder Singh]
|
||||
|
||||
* More thorough SSL support. #2370 [Roy Nicholson]
|
||||
|
|
|
@ -185,7 +185,7 @@ module ActiveResource
|
|||
#
|
||||
# Active Resource supports validations on resources and will return errors if any of these validations fail
|
||||
# (e.g., "First name can not be blank" and so on). These types of errors are denoted in the response by
|
||||
# a response code of <tt>422</tt> and an XML representation of the validation errors. The save operation will
|
||||
# a response code of <tt>422</tt> and an XML or JSON representation of the validation errors. The save operation will
|
||||
# then fail (with a <tt>false</tt> return value) and the validation errors can be accessed on the resource in question.
|
||||
#
|
||||
# ryan = Person.find(1)
|
||||
|
@ -194,10 +194,14 @@ module ActiveResource
|
|||
#
|
||||
# # When
|
||||
# # PUT http://api.people.com:3000/people/1.xml
|
||||
# # or
|
||||
# # PUT http://api.people.com:3000/people/1.json
|
||||
# # is requested with invalid values, the response is:
|
||||
# #
|
||||
# # Response (422):
|
||||
# # <errors type="array"><error>First cannot be empty</error></errors>
|
||||
# # or
|
||||
# # {"errors":["First cannot be empty"]}
|
||||
# #
|
||||
#
|
||||
# ryan.errors.invalid?(:first) # => true
|
||||
|
|
|
@ -7,11 +7,10 @@ module ActiveResource
|
|||
# Active Resource validation is reported to and from this object, which is used by Base#save
|
||||
# to determine whether the object in a valid state to be saved. See usage example in Validations.
|
||||
class Errors < ActiveModel::Errors
|
||||
# Grabs errors from the XML response.
|
||||
def from_xml(xml)
|
||||
# Grabs errors from an array of messages (like ActiveRecord::Validations)
|
||||
def from_array(messages)
|
||||
clear
|
||||
humanized_attributes = @base.attributes.keys.inject({}) { |h, attr_name| h.update(attr_name.humanize => attr_name) }
|
||||
messages = Array.wrap(Hash.from_xml(xml)['errors']['error']) rescue []
|
||||
messages.each do |message|
|
||||
attr_message = humanized_attributes.keys.detect do |attr_name|
|
||||
if message[0, attr_name.size + 1] == "#{attr_name} "
|
||||
|
@ -22,6 +21,18 @@ module ActiveResource
|
|||
self[:base] << message if attr_message.nil?
|
||||
end
|
||||
end
|
||||
|
||||
# Grabs errors from the json response.
|
||||
def from_json(json)
|
||||
array = ActiveSupport::JSON.decode(json)['errors'] rescue []
|
||||
from_array array
|
||||
end
|
||||
|
||||
# Grabs errors from the XML response.
|
||||
def from_xml(xml)
|
||||
array = Array.wrap(Hash.from_xml(xml)['errors']['error']) rescue []
|
||||
from_array array
|
||||
end
|
||||
end
|
||||
|
||||
# Module to support validation and errors with Active Resource objects. The module overrides
|
||||
|
@ -56,7 +67,12 @@ module ActiveResource
|
|||
save_without_validation
|
||||
true
|
||||
rescue ResourceInvalid => error
|
||||
errors.from_xml(error.response.body)
|
||||
case error.response['Content-Type']
|
||||
when 'application/xml'
|
||||
errors.from_xml(error.response.body)
|
||||
when 'application/json'
|
||||
errors.from_json(error.response.body)
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
|
|
|
@ -4,45 +4,80 @@ require "fixtures/person"
|
|||
class BaseErrorsTest < Test::Unit::TestCase
|
||||
def setup
|
||||
ActiveResource::HttpMock.respond_to do |mock|
|
||||
mock.post "/people.xml", {}, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><errors><error>Age can't be blank</error><error>Name can't be blank</error><error>Name must start with a letter</error><error>Person quota full for today.</error></errors>", 422
|
||||
mock.post "/people.xml", {}, %q(<?xml version="1.0" encoding="UTF-8"?><errors><error>Age can't be blank</error><error>Name can't be blank</error><error>Name must start with a letter</error><error>Person quota full for today.</error></errors>), 422, {'Content-Type' => 'application/xml'}
|
||||
mock.post "/people.json", {}, %q({"errors":["Age can't be blank","Name can't be blank","Name must start with a letter","Person quota full for today."]}), 422, {'Content-Type' => 'application/json'}
|
||||
end
|
||||
@person = Person.new(:name => '', :age => '')
|
||||
assert_equal @person.save, false
|
||||
end
|
||||
|
||||
def test_should_mark_as_invalid
|
||||
assert !@person.valid?
|
||||
[ :json, :xml ].each do |format|
|
||||
invalid_user_using_format(format) do
|
||||
assert !@person.valid?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_parse_xml_errors
|
||||
assert_kind_of ActiveResource::Errors, @person.errors
|
||||
assert_equal 4, @person.errors.size
|
||||
[ :json, :xml ].each do |format|
|
||||
invalid_user_using_format(format) do
|
||||
assert_kind_of ActiveResource::Errors, @person.errors
|
||||
assert_equal 4, @person.errors.size
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_parse_errors_to_individual_attributes
|
||||
assert @person.errors[:name].any?
|
||||
assert_equal ["can't be blank"], @person.errors[:age]
|
||||
assert_equal ["can't be blank", "must start with a letter"], @person.errors[:name]
|
||||
assert_equal ["Person quota full for today."], @person.errors[:base]
|
||||
[ :json, :xml ].each do |format|
|
||||
invalid_user_using_format(format) do
|
||||
assert @person.errors[:name].any?
|
||||
assert_equal ["can't be blank"], @person.errors[:age]
|
||||
assert_equal ["can't be blank", "must start with a letter"], @person.errors[:name]
|
||||
assert_equal ["Person quota full for today."], @person.errors[:base]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_iterate_over_errors
|
||||
errors = []
|
||||
@person.errors.each { |attribute, message| errors << [attribute.to_s, message] }
|
||||
assert errors.include?(["name", "can't be blank"])
|
||||
[ :json, :xml ].each do |format|
|
||||
invalid_user_using_format(format) do
|
||||
errors = []
|
||||
@person.errors.each { |attribute, message| errors << [attribute, message] }
|
||||
assert errors.include?([:name, "can't be blank"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_iterate_over_full_errors
|
||||
errors = []
|
||||
@person.errors.to_a.each { |message| errors << message }
|
||||
assert errors.include?("Name can't be blank")
|
||||
[ :json, :xml ].each do |format|
|
||||
invalid_user_using_format(format) do
|
||||
errors = []
|
||||
@person.errors.to_a.each { |message| errors << message }
|
||||
assert errors.include?("Name can't be blank")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_format_full_errors
|
||||
full = @person.errors.full_messages
|
||||
assert full.include?("Age can't be blank")
|
||||
assert full.include?("Name can't be blank")
|
||||
assert full.include?("Name must start with a letter")
|
||||
assert full.include?("Person quota full for today.")
|
||||
[ :json, :xml ].each do |format|
|
||||
invalid_user_using_format(format) do
|
||||
full = @person.errors.full_messages
|
||||
assert full.include?("Age can't be blank")
|
||||
assert full.include?("Name can't be blank")
|
||||
assert full.include?("Name must start with a letter")
|
||||
assert full.include?("Person quota full for today.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def invalid_user_using_format(mime_type_reference)
|
||||
previous_format = Person.format
|
||||
Person.format = mime_type_reference
|
||||
@person = Person.new(:name => '', :age => '')
|
||||
assert_equal false, @person.save
|
||||
|
||||
yield
|
||||
ensure
|
||||
Person.format = previous_format
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue