public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Format related patches to support serializing data out in the correct format 
with correct http request headers per http method type [#450 state:resolved]

Signed-off-by: Tarmo Tänav <tarmo@itech.ee>
Signed-off-by: Jeremy Kemper <jeremy@bitsweat.net>
rbpandey (author)
Fri Aug 29 18:19:18 -0700 2008
jeremy (committer)
Fri Aug 29 18:46:39 -0700 2008
commit  caabe228bc6c6e920043334d717e72093559e118
tree    86e236390fefbca50a9763e4041d7b9a3b0b85ae
parent  e7df4ce001fc5a7612c6b784ba2524f9b31cbc39
...
843
844
845
846
847
 
 
 
 
 
 
 
848
849
850
...
929
930
931
932
 
933
934
935
936
937
938
939
 
940
941
942
...
843
844
845
 
 
846
847
848
849
850
851
852
853
854
855
...
934
935
936
 
937
938
939
940
941
942
943
 
944
945
946
947
0
@@ -843,8 +843,13 @@ module ActiveResource
0
     #
0
     #   my_group.to_xml(:skip_instruct => true)
0
     #   # => <subsidiary_group> [...] </subsidiary_group>
0
-    def to_xml(options={})
0
-      attributes.to_xml({:root => self.class.element_name}.merge(options))
0
+    def encode(options={})
0
+      case self.class.format
0
+        when ActiveResource::Formats[:xml]
0
+          self.class.format.encode(attributes, {:root => self.class.element_name}.merge(options))
0
+        else
0
+          self.class.format.encode(attributes, options)
0
+      end
0
     end
0
 
0
     # A method to reload the attributes of this object from the remote web service.
0
@@ -929,14 +934,14 @@ module ActiveResource
0
 
0
       # Update the resource on the remote service.
0
       def update
0
-        returning connection.put(element_path(prefix_options), to_xml, self.class.headers) do |response|
0
+        returning connection.put(element_path(prefix_options), encode, self.class.headers) do |response|
0
           load_attributes_from_response(response)
0
         end
0
       end
0
 
0
       # Create (i.e., save to the remote service) the new resource.
0
       def create
0
-        returning connection.post(collection_path, to_xml, self.class.headers) do |response|
0
+        returning connection.post(collection_path, encode, self.class.headers) do |response|
0
           self.id = id_from_response(response)
0
           load_attributes_from_response(response)
0
         end
...
63
64
65
 
 
 
 
 
 
 
66
67
68
...
106
107
108
109
 
110
111
112
113
114
115
 
116
117
118
119
120
121
 
122
123
124
125
126
127
 
128
129
130
...
187
188
189
190
 
191
192
193
194
195
 
 
196
197
198
...
200
201
202
 
 
 
 
203
204
205
...
63
64
65
66
67
68
69
70
71
72
73
74
75
...
113
114
115
 
116
117
118
119
120
121
 
122
123
124
125
126
127
 
128
129
130
131
132
133
 
134
135
136
137
...
194
195
196
 
197
198
199
200
 
 
201
202
203
204
205
...
207
208
209
210
211
212
213
214
215
216
0
@@ -63,6 +63,13 @@ module ActiveResource
0
   # This class is used by ActiveResource::Base to interface with REST
0
   # services.
0
   class Connection
0
+
0
+    HTTP_FORMAT_HEADER_NAMES = {  :get => 'Accept',
0
+      :put => 'Content-Type',
0
+      :post => 'Content-Type',
0
+      :delete => 'Accept'
0
+    }
0
+
0
     attr_reader :site, :user, :password, :timeout
0
     attr_accessor :format
0
 
0
@@ -106,25 +113,25 @@ module ActiveResource
0
     # Execute a GET request.
0
     # Used to get (find) resources.
0
     def get(path, headers = {})
0
-      format.decode(request(:get, path, build_request_headers(headers)).body)
0
+      format.decode(request(:get, path, build_request_headers(headers, :get)).body)
0
     end
0
 
0
     # Execute a DELETE request (see HTTP protocol documentation if unfamiliar).
0
     # Used to delete resources.
0
     def delete(path, headers = {})
0
-      request(:delete, path, build_request_headers(headers))
0
+      request(:delete, path, build_request_headers(headers, :delete))
0
     end
0
 
0
     # Execute a PUT request (see HTTP protocol documentation if unfamiliar).
0
     # Used to update resources.
0
     def put(path, body = '', headers = {})
0
-      request(:put, path, body.to_s, build_request_headers(headers))
0
+      request(:put, path, body.to_s, build_request_headers(headers, :put))
0
     end
0
 
0
     # Execute a POST request.
0
     # Used to create new resources.
0
     def post(path, body = '', headers = {})
0
-      request(:post, path, body.to_s, build_request_headers(headers))
0
+      request(:post, path, body.to_s, build_request_headers(headers, :post))
0
     end
0
 
0
     # Execute a HEAD request.
0
@@ -187,12 +194,12 @@ module ActiveResource
0
       end
0
 
0
       def default_header
0
-        @default_header ||= { 'Content-Type' => format.mime_type }
0
+        @default_header ||= {}
0
       end
0
 
0
       # Builds headers for request to remote service.
0
-      def build_request_headers(headers)
0
-        authorization_header.update(default_header).update(headers)
0
+      def build_request_headers(headers, http_method=nil)
0
+        authorization_header.update(default_header).update(headers).update(http_format_header(http_method))
0
       end
0
 
0
       # Sets authorization header
0
@@ -200,6 +207,10 @@ module ActiveResource
0
         (@user || @password ? { 'Authorization' => 'Basic ' + ["#{@user}:#{ @password}"].pack('m').delete("\r\n") } : {})
0
       end
0
 
0
+      def http_format_header(http_method)
0
+        {HTTP_FORMAT_HEADER_NAMES[http_method] => format.mime_type}
0
+      end
0
+
0
       def logger #:nodoc:
0
         ActiveResource::Base.logger
0
       end
...
30
31
32
33
 
34
35
36
...
83
84
85
86
 
87
88
89
90
91
92
 
 
 
93
94
 
95
96
 
97
98
99
 
100
101
102
103
 
104
105
106
...
110
111
112
113
 
114
115
116
...
30
31
32
 
33
34
35
36
...
83
84
85
 
86
87
88
89
90
 
 
91
92
93
94
 
95
96
 
97
98
99
 
100
101
102
103
 
104
105
106
107
...
111
112
113
 
114
115
116
117
0
@@ -30,7 +30,7 @@ module ActiveResource
0
   #   Person.get(:active)  # GET /people/active.xml
0
   #   # => [{:id => 1, :name => 'Ryan'}, {:id => 2, :name => 'Joe'}]
0
   #
0
-  module CustomMethods 
0
+  module CustomMethods
0
     def self.included(base)
0
       base.class_eval do
0
         extend ActiveResource::CustomMethods::ClassMethods
0
@@ -83,24 +83,25 @@ module ActiveResource
0
         "#{prefix(prefix_options)}#{collection_name}/#{method_name}.#{format.extension}#{query_string(query_options)}"
0
       end
0
     end
0
-    
0
+
0
     module InstanceMethods
0
       def get(method_name, options = {})
0
         connection.get(custom_method_element_url(method_name, options), self.class.headers)
0
       end
0
-      
0
-      def post(method_name, options = {}, body = '')
0
+
0
+      def post(method_name, options = {}, body = nil)
0
+        request_body = body.nil? ? encode : body
0
         if new?
0
-          connection.post(custom_method_new_element_url(method_name, options), (body.nil? ? to_xml : body), self.class.headers)
0
+          connection.post(custom_method_new_element_url(method_name, options), request_body, self.class.headers)
0
         else
0
-          connection.post(custom_method_element_url(method_name, options), body, self.class.headers)
0
+          connection.post(custom_method_element_url(method_name, options), request_body, self.class.headers)
0
         end
0
       end
0
-      
0
+
0
       def put(method_name, options = {}, body = '')
0
         connection.put(custom_method_element_url(method_name, options), body, self.class.headers)
0
       end
0
-      
0
+
0
       def delete(method_name, options = {})
0
         connection.delete(custom_method_element_url(method_name, options), self.class.headers)
0
       end
0
@@ -110,7 +111,7 @@ module ActiveResource
0
         def custom_method_element_url(method_name, options = {})
0
           "#{self.class.prefix(prefix_options)}#{self.class.collection_name}/#{id}/#{method_name}.#{self.class.format.extension}#{self.class.send!(:query_string, options)}"
0
         end
0
-      
0
+
0
         def custom_method_new_element_url(method_name, options = {})
0
           "#{self.class.prefix(prefix_options)}#{self.class.collection_name}/new/#{method_name}.#{self.class.format.extension}#{self.class.send!(:query_string, options)}"
0
         end
...
2
3
4
5
 
6
7
8
9
 
10
11
12
13
14
 
 
15
16
17
 
18
19
20
21
22
23
24
 
...
2
3
4
 
5
6
7
8
 
9
10
11
12
 
 
13
14
15
16
 
17
18
19
20
21
22
 
23
24
0
@@ -2,22 +2,22 @@ module ActiveResource
0
   module Formats
0
     module JsonFormat
0
       extend self
0
-      
0
+
0
       def extension
0
         "json"
0
       end
0
-      
0
+
0
       def mime_type
0
         "application/json"
0
       end
0
-      
0
-      def encode(hash)
0
+
0
+      def encode(hash, options={})
0
         hash.to_json
0
       end
0
-      
0
+
0
       def decode(json)
0
         ActiveSupport::JSON.decode(json)
0
       end
0
     end
0
   end
0
-end
0
\ No newline at end of file
0
+end
...
2
3
4
5
 
6
7
8
9
 
10
11
12
13
14
15
 
 
 
16
17
 
18
19
20
21
 
22
23
24
...
28
29
30
31
 
32
33
34
35
 
...
2
3
4
 
5
6
7
8
 
9
10
11
12
 
 
 
13
14
15
16
 
17
18
19
20
 
21
22
23
24
...
28
29
30
 
31
32
33
 
34
35
0
@@ -2,23 +2,23 @@ module ActiveResource
0
   module Formats
0
     module XmlFormat
0
       extend self
0
-      
0
+
0
       def extension
0
         "xml"
0
       end
0
-      
0
+
0
       def mime_type
0
         "application/xml"
0
       end
0
-      
0
-      def encode(hash)
0
-        hash.to_xml
0
+
0
+      def encode(hash, options={})
0
+        hash.to_xml(options)
0
       end
0
-      
0
+
0
       def decode(xml)
0
         from_xml_data(Hash.from_xml(xml))
0
       end
0
-      
0
+
0
       private
0
         # Manipulate from_xml Hash, because xml_simple is not exactly what we
0
         # want for Active Resource.
0
@@ -28,7 +28,7 @@ module ActiveResource
0
           else
0
             data
0
           end
0
-        end      
0
+        end
0
     end
0
   end
0
-end
0
\ No newline at end of file
0
+end
...
146
147
148
149
 
150
151
152
...
146
147
148
 
149
150
151
152
0
@@ -146,7 +146,7 @@ module ActiveResource
0
     attr_accessor :path, :method, :body, :headers
0
 
0
     def initialize(method, path, body = nil, headers = {})
0
-      @method, @path, @body, @headers = method, path, body, headers.reverse_merge('Content-Type' => 'application/xml')
0
+      @method, @path, @body, @headers = method, path, body, headers.merge(ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[method] => 'application/xml')
0
     end
0
 
0
     def ==(other_request)
...
10
11
12
13
14
 
15
16
17
...
10
11
12
 
 
13
14
15
16
0
@@ -10,8 +10,7 @@ class CustomMethodsTest < Test::Unit::TestCase
0
     @ryan  = { :name => 'Ryan' }.to_xml(:root => 'person')
0
     @addy  = { :id => 1, :street => '12345 Street' }.to_xml(:root => 'address')
0
     @addy_deep  = { :id => 1, :street => '12345 Street', :zip => "27519" }.to_xml(:root => 'address')
0
-    @default_request_headers = { 'Content-Type' => 'application/xml' }
0
-    
0
+
0
     ActiveResource::HttpMock.respond_to do |mock|
0
       mock.get    "/people/1.xml",             {}, @matz
0
       mock.get    "/people/1/shallow.xml", {}, @matz
...
819
820
821
822
 
823
824
825
...
819
820
821
 
822
823
824
825
0
@@ -819,7 +819,7 @@ class BaseTest < Test::Unit::TestCase
0
   
0
   def test_to_xml
0
     matz = Person.find(1)
0
-    xml = matz.to_xml
0
+    xml = matz.encode
0
     assert xml.starts_with?('<?xml version="1.0" encoding="UTF-8"?>')
0
     assert xml.include?('<name>Matz</name>')
0
     assert xml.include?('<id type="integer">1</id>')
...
5
6
7
8
 
9
10
11
 
 
 
 
 
 
 
 
 
12
13
14
15
 
16
17
18
...
21
22
23
24
 
25
26
27
...
32
33
34
35
 
36
37
38
...
40
41
42
43
 
44
45
46
47
48
49
 
 
50
51
52
...
57
58
59
60
61
 
 
 
 
 
62
63
64
65
66
 
67
68
69
70
71
72
73
 
74
75
76
...
5
6
7
 
8
9
10
 
11
12
13
14
15
16
17
18
19
20
21
22
 
23
24
25
26
...
29
30
31
 
32
33
34
35
...
40
41
42
 
43
44
45
46
...
48
49
50
 
51
52
53
54
55
 
 
56
57
58
59
60
...
65
66
67
 
68
69
70
71
72
73
74
75
76
77
 
78
79
80
81
82
83
84
 
85
86
87
88
0
@@ -5,14 +5,22 @@ class FormatTest < Test::Unit::TestCase
0
   def setup
0
     @matz  = { :id => 1, :name => 'Matz' }
0
     @david = { :id => 2, :name => 'David' }
0
-    
0
+
0
     @programmers = [ @matz, @david ]
0
   end
0
-  
0
+
0
+  def test_http_format_header_name
0
+    header_name = ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:get]
0
+    assert_equal 'Accept', header_name
0
+
0
+    headers_names = [ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:put], ActiveResource::Connection::HTTP_FORMAT_HEADER_NAMES[:post]]
0
+    headers_names.each{|header_name| assert_equal 'Content-Type', header_name}
0
+  end
0
+
0
   def test_formats_on_single_element
0
     for format in [ :json, :xml ]
0
       using_format(Person, format) do
0
-        ActiveResource::HttpMock.respond_to.get "/people/1.#{format}", {}, ActiveResource::Formats[format].encode(@david)
0
+        ActiveResource::HttpMock.respond_to.get "/people/1.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@david)
0
         assert_equal @david[:name], Person.find(1).name
0
       end
0
     end
0
@@ -21,7 +29,7 @@ class FormatTest < Test::Unit::TestCase
0
   def test_formats_on_collection
0
     for format in [ :json, :xml ]
0
       using_format(Person, format) do
0
-        ActiveResource::HttpMock.respond_to.get "/people.#{format}", {}, ActiveResource::Formats[format].encode(@programmers)
0
+        ActiveResource::HttpMock.respond_to.get "/people.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@programmers)
0
         remote_programmers = Person.find(:all)
0
         assert_equal 2, remote_programmers.size
0
         assert remote_programmers.select { |p| p.name == 'David' }
0
@@ -32,7 +40,7 @@ class FormatTest < Test::Unit::TestCase
0
   def test_formats_on_custom_collection_method
0
     for format in [ :json, :xml ]
0
       using_format(Person, format) do
0
-        ActiveResource::HttpMock.respond_to.get "/people/retrieve.#{format}?name=David", {}, ActiveResource::Formats[format].encode([@david])
0
+        ActiveResource::HttpMock.respond_to.get "/people/retrieve.#{format}?name=David", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode([@david])
0
         remote_programmers = Person.get(:retrieve, :name => 'David')
0
         assert_equal 1, remote_programmers.size
0
         assert_equal @david[:id], remote_programmers[0]['id']
0
@@ -40,13 +48,13 @@ class FormatTest < Test::Unit::TestCase
0
       end
0
     end
0
   end
0
-  
0
+
0
   def test_formats_on_custom_element_method
0
     for format in [ :json, :xml ]
0
       using_format(Person, format) do
0
         ActiveResource::HttpMock.respond_to do |mock|
0
-          mock.get "/people/2.#{format}", {}, ActiveResource::Formats[format].encode(@david)
0
-          mock.get "/people/2/shallow.#{format}", {}, ActiveResource::Formats[format].encode(@david)
0
+          mock.get "/people/2.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@david)
0
+          mock.get "/people/2/shallow.#{format}", {'Accept' => ActiveResource::Formats[format].mime_type}, ActiveResource::Formats[format].encode(@david)
0
         end
0
         remote_programmer = Person.find(2).get(:shallow)
0
         assert_equal @david[:id], remote_programmer['id']
0
@@ -57,20 +65,24 @@ class FormatTest < Test::Unit::TestCase
0
     for format in [ :json, :xml ]
0
       ryan = ActiveResource::Formats[format].encode({ :name => 'Ryan' })
0
       using_format(Person, format) do
0
-        ActiveResource::HttpMock.respond_to.post "/people/new/register.#{format}", {}, ryan, 201, 'Location' => "/people/5.#{format}"
0
         remote_ryan = Person.new(:name => 'Ryan')
0
+        ActiveResource::HttpMock.respond_to.post "/people.#{format}", {'Content-Type' => ActiveResource::Formats[format].mime_type}, ryan, 201, {'Location' => "/people/5.#{format}"}
0
+        remote_ryan.save
0
+
0
+        remote_ryan = Person.new(:name => 'Ryan')
0
+        ActiveResource::HttpMock.respond_to.post "/people/new/register.#{format}", {'Content-Type' => ActiveResource::Formats[format].mime_type}, ryan, 201, {'Location' => "/people/5.#{format}"}
0
         assert_equal ActiveResource::Response.new(ryan, 201, {'Location' => "/people/5.#{format}"}), remote_ryan.post(:register)
0
       end
0
     end
0
   end
0
-  
0
+
0
   def test_setting_format_before_site
0
     resource = Class.new(ActiveResource::Base)
0
     resource.format = :json
0
     resource.site   = 'http://37s.sunrise.i:3000'
0
     assert_equal ActiveResource::Formats[:json], resource.connection.format
0
   end
0
-  
0
+
0
   private
0
     def using_format(klass, mime_type_reference)
0
       previous_format = klass.format

Comments