Skip to content
This repository
Browse code

add handling for backwards-compatibility and update documentation

  • Loading branch information...
commit 02859745cc0db02fcb1af27da345456a3b5e1eb2 1 parent 7c307c2
Matt Jones authored February 04, 2012
13  activeresource/lib/active_resource/base.rb
@@ -234,7 +234,7 @@ module ActiveResource
234 234
   #   ryan.save  # => false
235 235
   #
236 236
   #   # When
237  
-  #   # PUT https://api.people.com/people/1.json
  237
+  #   # PUT https://api.people.com/people/1.xml
238 238
   #   # or
239 239
   #   # PUT https://api.people.com/people/1.json
240 240
   #   # is requested with invalid values, the response is:
@@ -242,12 +242,21 @@ module ActiveResource
242 242
   #   # Response (422):
243 243
   #   # <errors><error>First cannot be empty</error></errors>
244 244
   #   # or
245  
-  #   # {"errors":["First cannot be empty"]}
  245
+  #   # {"errors":{"first":["cannot be empty"]}}
246 246
   #   #
247 247
   #
248 248
   #   ryan.errors.invalid?(:first)  # => true
249 249
   #   ryan.errors.full_messages     # => ['First cannot be empty']
250 250
   #
  251
+  # For backwards-compatibility with older endpoints, the following formats are also supported in JSON responses:
  252
+  #
  253
+  #   # {"errors":['First cannot be empty']}
  254
+  #   #   This was the required format for previous versions of ActiveResource
  255
+  #   # {"first":["cannot be empty"]}
  256
+  #   #   This was the default format produced by respond_with in ActionController <3.2.1
  257
+  #
  258
+  # Parsing either of these formats will result in a deprecation warning.
  259
+  #
251 260
   # Learn more about Active Resource's validation features in the ActiveResource::Validations documentation.
252 261
   #
253 262
   # === Timeouts
28  activeresource/lib/active_resource/validations.rb
@@ -25,6 +25,12 @@ def from_array(messages, save_cache = false)
25 25
       end
26 26
     end
27 27
 
  28
+    # Grabs errors from a hash of attribute => array of errors elements
  29
+    # The second parameter directs the errors cache to be cleared (default)
  30
+    # or not (by passing true)
  31
+    #
  32
+    # Unrecognized attribute names will be humanized and added to the record's
  33
+    # base errors.
28 34
     def from_hash(messages, save_cache = false)
29 35
       clear unless save_cache
30 36
 
@@ -32,7 +38,11 @@ def from_hash(messages, save_cache = false)
32 38
         errors.each do |error|
33 39
           if @base.attributes.keys.include?(key)
34 40
             add key, error
  41
+          elsif key == 'base'
  42
+            self[:base] << error
35 43
           else
  44
+            # reporting an error on an attribute not in attributes
  45
+            # format and add them to base
36 46
             self[:base] << "#{key.humanize} #{error}"
37 47
           end
38 48
         end
@@ -41,8 +51,22 @@ def from_hash(messages, save_cache = false)
41 51
 
42 52
     # Grabs errors from a json response.
43 53
     def from_json(json, save_cache = false)
44  
-      hash = ActiveSupport::JSON.decode(json)['errors'] || {} rescue {}
45  
-      from_hash hash, save_cache
  54
+      decoded = ActiveSupport::JSON.decode(json) || {} rescue {}
  55
+      if decoded.kind_of?(Hash) && (decoded.has_key?('errors') || decoded.empty?)
  56
+        errors = decoded['errors'] || {}
  57
+        if errors.kind_of?(Array)
  58
+          # 3.2.1-style with array of strings
  59
+          ActiveSupport::Deprecation.warn('Returning errors as an array of strings is deprecated.')
  60
+          from_array errors, save_cache
  61
+        else
  62
+          # 3.2.2+ style
  63
+          from_hash errors, save_cache
  64
+        end
  65
+      else
  66
+        # <3.2-style respond_with - lacks 'errors' key
  67
+        ActiveSupport::Deprecation.warn('Returning errors as a hash without a root "errors" key is deprecated.')
  68
+        from_hash decoded, save_cache
  69
+      end
46 70
     end
47 71
 
48 72
     # Grabs errors from an XML response.
30  activeresource/test/cases/base_errors_test.rb
@@ -93,6 +93,36 @@ def test_should_mark_as_invalid_when_content_type_is_unavailable_in_response_hea
93 93
     end
94 94
   end
95 95
 
  96
+  def test_should_parse_json_string_errors_with_an_errors_key
  97
+    ActiveResource::HttpMock.respond_to do |mock|
  98
+      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; charset=utf-8'}
  99
+    end
  100
+
  101
+    assert_deprecated(/as an array/) do
  102
+      invalid_user_using_format(:json) do
  103
+        assert @person.errors[:name].any?
  104
+        assert_equal ["can't be blank"], @person.errors[:age]
  105
+        assert_equal ["can't be blank", "must start with a letter"], @person.errors[:name]
  106
+        assert_equal ["Person quota full for today."], @person.errors[:base]
  107
+      end
  108
+    end
  109
+  end
  110
+
  111
+  def test_should_parse_3_1_style_json_errors
  112
+    ActiveResource::HttpMock.respond_to do |mock|
  113
+      mock.post "/people.json", {}, %q({"age":["can't be blank"],"name":["can't be blank", "must start with a letter"],"person":["quota full for today."]}), 422, {'Content-Type' => 'application/json; charset=utf-8'}
  114
+    end
  115
+
  116
+    assert_deprecated(/without a root/) do
  117
+      invalid_user_using_format(:json) do
  118
+        assert @person.errors[:name].any?
  119
+        assert_equal ["can't be blank"], @person.errors[:age]
  120
+        assert_equal ["can't be blank", "must start with a letter"], @person.errors[:name]
  121
+        assert_equal ["Person quota full for today."], @person.errors[:base]
  122
+      end
  123
+    end
  124
+  end
  125
+
96 126
   private
97 127
   def invalid_user_using_format(mime_type_reference)
98 128
     previous_format = Person.format

0 notes on commit 0285974

Please sign in to comment.
Something went wrong with that request. Please try again.