├── .gitignore
├── .travis.yml
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── actionpack-xml_parser.gemspec
├── gemfiles
└── Gemfile-edge
├── lib
├── action_pack
│ ├── xml_parser.rb
│ └── xml_parser
│ │ ├── railtie.rb
│ │ └── version.rb
└── actionpack-xml_parser.rb
└── test
├── fixtures
└── 500.html
├── helper.rb
├── webservice_test.rb
└── xml_params_parsing_test.rb
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | *.rbc
3 | .bundle
4 | .config
5 | .yardoc
6 | *.lock
7 | InstalledFiles
8 | _yardoc
9 | coverage
10 | doc/
11 | lib/bundler/man
12 | pkg
13 | rdoc
14 | spec/reports
15 | test/tmp
16 | test/version_tmp
17 | tmp
18 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: ruby
2 | sudo: false
3 | rvm:
4 | - 2.2.5
5 | - 2.3.1
6 | - ruby-head
7 | gemfile:
8 | - gemfiles/Gemfile-edge
9 | - Gemfile
10 | notifications:
11 | email: false
12 | matrix:
13 | fast_finish: true
14 | allow_failures:
15 | - rvm: ruby-head
16 | cache: bundler
17 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Prem Sichanugrist
2 |
3 | MIT License
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining
6 | a copy of this software and associated documentation files (the
7 | "Software"), to deal in the Software without restriction, including
8 | without limitation the rights to use, copy, modify, merge, publish,
9 | distribute, sublicense, and/or sell copies of the Software, and to
10 | permit persons to whom the Software is furnished to do so, subject to
11 | the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be
14 | included in all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | actionpack-xml\_parser
2 | ======================
3 |
4 | A XML parameters parser for Action Pack (removed from core in Rails 4.0)
5 |
6 | Installation
7 | ------------
8 |
9 | Include this gem into your Gemfile:
10 |
11 | ```ruby
12 | gem 'actionpack-xml_parser'
13 | ```
14 |
15 | Parameters parsing rules
16 | ------------------------
17 |
18 | The parameters parsing is handled by `ActiveSupport::XMLConverter` so there may
19 | be specific features and subtle differences depending on the chosen XML backend.
20 |
21 | ### Hashes
22 |
23 | Basically, each node represents a key. With the following XML:
24 |
25 | ```xml
26 | David
27 | ```
28 |
29 | The resulting parameters will be:
30 |
31 | ```ruby
32 | {"person" => {"name" => "David"}}
33 | ```
34 |
35 | ### File attachment
36 |
37 | You can specify the `type` attribute of a node to attach files:
38 |
39 | ```xml
40 |
41 |
42 |
43 | ```
44 |
45 | The resulting parameters will include a `StringIO` object with the given content,
46 | name and content type set accordingly:
47 |
48 | ```ruby
49 | {"person" => {"avatar" => #}}
50 | ```
51 |
52 | ### Arrays
53 |
54 | There are several ways to pass an array. You can either specify multiple nodes
55 | with the same name:
56 |
57 | ```xml
58 |
59 |
60 |
61 |
62 | ```
63 |
64 | The resulting parameters will be:
65 |
66 | ```ruby
67 | {"person" => {"address" => [{"city" => "Chicago"}, {"city" => "Ottawa"}]}}
68 | ```
69 |
70 | You can also specify the `type` attribute of a node and nest child nodes inside:
71 |
72 | ```xml
73 |
74 |
75 |
76 |
77 |
78 |
79 | ```
80 |
81 | will result in:
82 |
83 | ```ruby
84 | {"person" => {"addresses" => [{"city" => "Melbourne"}, {"city" => "Paris"}]}}
85 | ```
86 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env rake
2 | require "bundler/gem_tasks"
3 | require 'rake/testtask'
4 |
5 | Rake::TestTask.new do |t|
6 | t.libs = ["test"]
7 | t.pattern = "test/**/*_test.rb"
8 | t.ruby_opts = ['-w']
9 | end
10 |
11 | task :default => :test
12 |
--------------------------------------------------------------------------------
/actionpack-xml_parser.gemspec:
--------------------------------------------------------------------------------
1 | $:.push File.expand_path("../lib", __FILE__)
2 | require "action_pack/xml_parser/version"
3 |
4 | Gem::Specification.new do |s|
5 | s.platform = Gem::Platform::RUBY
6 | s.name = 'actionpack-xml_parser'
7 | s.version = ActionPack::XmlParser::VERSION
8 | s.summary = 'XML parameters parser for Action Pack (removed from core in Rails 4.0)'
9 |
10 | s.required_ruby_version = '>= 2.2.2'
11 | s.license = 'MIT'
12 |
13 | s.author = 'Prem Sichanugrist'
14 | s.email = 's@sikac.hu'
15 | s.homepage = 'http://www.rubyonrails.org'
16 |
17 | s.files = Dir['LICENSE', 'README.md', 'lib/**/*']
18 | s.require_path = 'lib'
19 |
20 | s.extra_rdoc_files = %w( README.md )
21 | s.rdoc_options.concat ['--main', 'README.md']
22 |
23 | s.add_dependency('actionpack', '>= 5.0')
24 | s.add_dependency('railties', '>= 5.0')
25 |
26 | s.add_development_dependency('rake')
27 | end
28 |
--------------------------------------------------------------------------------
/gemfiles/Gemfile-edge:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec path: '..'
4 |
5 | gem 'actionpack', github: 'rails/rails', branch: 'master'
6 | gem 'railties', github: 'rails/rails', branch: 'master'
7 |
--------------------------------------------------------------------------------
/lib/action_pack/xml_parser.rb:
--------------------------------------------------------------------------------
1 | require 'active_support'
2 | require 'active_support/core_ext/hash/conversions'
3 | require 'action_dispatch'
4 | require 'action_dispatch/http/request'
5 | require 'action_pack/xml_parser/version'
6 |
7 | module ActionPack
8 | class XmlParser
9 | def self.register
10 | original_parsers = ActionDispatch::Request.parameter_parsers
11 | ActionDispatch::Request.parameter_parsers = original_parsers.merge(Mime[:xml].symbol => self)
12 | end
13 |
14 | def self.call(raw_post)
15 | Hash.from_xml(raw_post) || {}
16 | end
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/action_pack/xml_parser/railtie.rb:
--------------------------------------------------------------------------------
1 | require 'action_pack/xml_parser'
2 |
3 | module ActionPack
4 | class XmlParser
5 | class Railtie < ::Rails::Railtie
6 | initializer "actionpack-xml_parser.configure" do
7 | ActionPack::XmlParser.register
8 | end
9 | end
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/action_pack/xml_parser/version.rb:
--------------------------------------------------------------------------------
1 | module ActionPack
2 | class XmlParser
3 | VERSION = "2.0.1"
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/lib/actionpack-xml_parser.rb:
--------------------------------------------------------------------------------
1 | require 'action_pack/xml_parser/railtie' if defined?(Rails::Railtie)
2 |
--------------------------------------------------------------------------------
/test/fixtures/500.html:
--------------------------------------------------------------------------------
1 | 500 error fixture
2 |
--------------------------------------------------------------------------------
/test/helper.rb:
--------------------------------------------------------------------------------
1 | require 'bundler/setup'
2 |
3 | require 'active_support/testing/autorun'
4 | require 'action_pack/xml_parser'
5 | require 'action_controller'
6 |
7 | FIXTURE_LOAD_PATH = File.join(File.dirname(__FILE__), 'fixtures')
8 | SharedTestRoutes = ActionDispatch::Routing::RouteSet.new
9 |
10 | module ActionDispatch
11 | module SharedRoutes
12 | def before_setup
13 | @routes = SharedTestRoutes
14 | super
15 | end
16 | end
17 | end
18 |
19 | class RoutedRackApp
20 | attr_reader :routes
21 |
22 | def initialize(routes, &blk)
23 | @routes = routes
24 | @stack = ActionDispatch::MiddlewareStack.new(&blk).build(@routes)
25 | end
26 |
27 | def call(env)
28 | @stack.call(env)
29 | end
30 | end
31 |
32 | class ActionDispatch::IntegrationTest < ActiveSupport::TestCase
33 | include ActionDispatch::SharedRoutes
34 |
35 | ActionPack::XmlParser.register
36 |
37 | def self.build_app(routes = nil)
38 | RoutedRackApp.new(routes || ActionDispatch::Routing::RouteSet.new) do |middleware|
39 | middleware.use ActionDispatch::ShowExceptions, ActionDispatch::PublicExceptions.new(FIXTURE_LOAD_PATH)
40 | middleware.use Rack::Head
41 | yield(middleware) if block_given?
42 | end
43 | end
44 |
45 | self.app = build_app
46 |
47 | # Stub Rails dispatcher so it does not get controller references and
48 | # simply return the controller#action as Rack::Body.
49 | class StubDispatcher < ::ActionDispatch::Routing::RouteSet::Dispatcher
50 | protected
51 | def controller_reference(controller_param)
52 | controller_param
53 | end
54 |
55 | def dispatch(controller, action, env)
56 | [200, {'Content-Type' => 'text/html'}, ["#{controller}##{action}"]]
57 | end
58 | end
59 |
60 | def self.stub_controllers
61 | old_dispatcher = ActionDispatch::Routing::RouteSet::Dispatcher
62 | ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
63 | ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, StubDispatcher }
64 | yield ActionDispatch::Routing::RouteSet.new
65 | ensure
66 | ActionDispatch::Routing::RouteSet.module_eval { remove_const :Dispatcher }
67 | ActionDispatch::Routing::RouteSet.module_eval { const_set :Dispatcher, old_dispatcher }
68 | end
69 |
70 | def with_routing(&block)
71 | temporary_routes = ActionDispatch::Routing::RouteSet.new
72 | old_app, self.class.app = self.class.app, self.class.build_app(temporary_routes)
73 | old_routes = SharedTestRoutes
74 | silence_warnings { Object.const_set(:SharedTestRoutes, temporary_routes) }
75 |
76 | yield temporary_routes
77 | ensure
78 | self.class.app = old_app
79 | silence_warnings { Object.const_set(:SharedTestRoutes, old_routes) }
80 | end
81 | end
82 |
--------------------------------------------------------------------------------
/test/webservice_test.rb:
--------------------------------------------------------------------------------
1 | require 'helper'
2 |
3 | class WebServiceTest < ActionDispatch::IntegrationTest
4 | class TestController < ActionController::Base
5 | def assign_parameters
6 | if params[:full]
7 | render plain: dump_params_keys
8 | else
9 | render plain: (params.keys - ['controller', 'action']).sort.join(", ")
10 | end
11 | end
12 |
13 | def dump_params_keys(hash = params)
14 | hash.keys.sort.inject("") do |s, k|
15 | value = hash[k]
16 |
17 | if value.is_a?(Hash) || value.is_a?(ActionController::Parameters)
18 | value = "(#{dump_params_keys(value)})"
19 | else
20 | value = ""
21 | end
22 |
23 | s << ", " unless s.empty?
24 | s << "#{k}#{value}"
25 | end
26 | end
27 | end
28 |
29 | def setup
30 | @controller = TestController.new
31 | @integration_session = nil
32 | end
33 |
34 | def test_check_parameters
35 | with_test_route_set do
36 | get "/"
37 | assert_equal '', @controller.response.body
38 | end
39 | end
40 |
41 | def test_post_xml
42 | with_test_route_set do
43 | post "/", params: 'content...',
44 | headers: {'CONTENT_TYPE' => 'application/xml'}
45 |
46 | assert_equal 'entry', @controller.response.body
47 | assert @controller.params.has_key?(:entry)
48 | assert_equal 'content...', @controller.params["entry"]['summary']
49 | assert_equal 'true', @controller.params["entry"]['attributed']
50 | end
51 | end
52 |
53 | def test_put_xml
54 | with_test_route_set do
55 | put "/", params: 'content...',
56 | headers: {'CONTENT_TYPE' => 'application/xml'}
57 |
58 | assert_equal 'entry', @controller.response.body
59 | assert @controller.params.has_key?(:entry)
60 | assert_equal 'content...', @controller.params["entry"]['summary']
61 | assert_equal 'true', @controller.params["entry"]['attributed']
62 | end
63 | end
64 |
65 | def test_put_xml_using_a_type_node
66 | with_test_route_set do
67 | put "/", params: 'content...',
68 | headers: {'CONTENT_TYPE' => 'application/xml'}
69 |
70 | assert_equal 'type', @controller.response.body
71 | assert @controller.params.has_key?(:type)
72 | assert_equal 'content...', @controller.params["type"]['summary']
73 | assert_equal 'true', @controller.params["type"]['attributed']
74 | end
75 | end
76 |
77 | def test_put_xml_using_a_type_node_and_attribute
78 | with_test_route_set do
79 | put "/", params: 'false',
80 | headers: {'CONTENT_TYPE' => 'application/xml'}
81 |
82 | assert_equal 'type', @controller.response.body
83 | assert @controller.params.has_key?(:type)
84 | assert_equal false, @controller.params["type"]['summary']
85 | assert_equal 'true', @controller.params["type"]['attributed']
86 | end
87 | end
88 |
89 | def test_post_xml_using_a_type_node
90 | with_test_route_set do
91 | post "/", params: 'arial',
92 | headers: {'CONTENT_TYPE' => 'application/xml'}
93 |
94 | assert_equal 'font', @controller.response.body
95 | assert @controller.params.has_key?(:font)
96 | assert_equal 'arial', @controller.params['font']['type']
97 | assert_equal 'true', @controller.params["font"]['attributed']
98 | end
99 | end
100 |
101 | def test_post_xml_using_a_root_node_named_type
102 | with_test_route_set do
103 | post "/", params: '33',
104 | headers: {'CONTENT_TYPE' => 'application/xml'}
105 |
106 | assert @controller.params.has_key?(:type)
107 | assert_equal 33, @controller.params['type']
108 | end
109 | end
110 |
111 | def test_post_xml_using_an_attributted_node_named_type
112 | with_test_route_set do
113 | with_params_parsers Mime[:xml].symbol => Proc.new { |data| Hash.from_xml(data)['request'].with_indifferent_access } do
114 | post "/", params: 'Arial,123',
115 | headers: {'CONTENT_TYPE' => 'application/xml'}
116 |
117 | assert_equal 'type, z', @controller.response.body
118 | assert @controller.params.has_key?(:type)
119 | assert_equal 'Arial,12', @controller.params['type'], @controller.params.inspect
120 | assert_equal '3', @controller.params['z'], @controller.params.inspect
121 | end
122 | end
123 | end
124 |
125 | def test_post_xml_using_a_disallowed_type_attribute
126 | $stderr = StringIO.new
127 | with_test_route_set do
128 | post '/', params: 'value', headers: {'CONTENT_TYPE' => 'application/xml'}
129 | assert_response 400
130 |
131 | post '/', params: 'value', headers: {'CONTENT_TYPE' => 'application/xml'}
132 | assert_response 400
133 | end
134 | ensure
135 | $stderr = STDERR
136 | end
137 |
138 | def test_register_and_use_xml_simple
139 | with_test_route_set do
140 | with_params_parsers Mime[:xml].symbol => Proc.new { |data| Hash.from_xml(data)['request'].with_indifferent_access } do
141 | post "/", params: 'content...SimpleXml',
142 | headers: {'CONTENT_TYPE' => 'application/xml'}
143 |
144 | assert_equal 'summary, title', @controller.response.body
145 | assert @controller.params.has_key?(:summary)
146 | assert @controller.params.has_key?(:title)
147 | assert_equal 'content...', @controller.params["summary"]
148 | assert_equal 'SimpleXml', @controller.params["title"]
149 | end
150 | end
151 | end
152 |
153 | def test_use_xml_ximple_with_empty_request
154 | with_test_route_set do
155 | assert_nothing_raised { post "/", params: "", headers: {'CONTENT_TYPE' => 'application/xml'} }
156 | assert_equal '', @controller.response.body
157 | end
158 | end
159 |
160 | def test_dasherized_keys_as_xml
161 | with_test_route_set do
162 | post "/?full=1", params: "\n...\n",
163 | headers: {'CONTENT_TYPE' => 'application/xml'}
164 | assert_equal 'action, controller, first_key(sub_key), full', @controller.response.body
165 | assert_equal "...", @controller.params[:first_key][:sub_key]
166 | end
167 | end
168 |
169 | def test_typecast_as_xml
170 | with_test_route_set do
171 | xml = <<-XML
172 |
173 | 15
174 | false
175 | true
176 | 2005-03-17
177 | 2005-03-17T21:41:07Z
178 | unparsed
179 | 1
180 | hello
181 | 1974-07-25
182 |
183 | XML
184 | post "/", params: xml, headers: {'CONTENT_TYPE' => 'application/xml'}
185 |
186 | params = @controller.params
187 | assert_equal 15, params[:data][:a]
188 | assert_equal false, params[:data][:b]
189 | assert_equal true, params[:data][:c]
190 | assert_equal Date.new(2005,3,17), params[:data][:d]
191 | assert_equal Time.utc(2005,3,17,21,41,7), params[:data][:e]
192 | assert_equal "unparsed", params[:data][:f]
193 | assert_equal [1, "hello", Date.new(1974,7,25)], params[:data][:g]
194 | end
195 | end
196 |
197 | def test_entities_unescaped_as_xml_simple
198 | with_test_route_set do
199 | xml = <<-XML
200 | <foo "bar's" & friends>
201 | XML
202 | post "/", params: xml, headers: {'CONTENT_TYPE' => 'application/xml'}
203 | assert_equal %(), @controller.params[:data]
204 | end
205 | end
206 |
207 | private
208 | def with_params_parsers(parsers = {})
209 | old_session = @integration_session
210 | original_parsers = ActionDispatch::Request.parameter_parsers
211 | ActionDispatch::Request.parameter_parsers = original_parsers.merge parsers
212 | reset!
213 | yield
214 | ensure
215 | ActionDispatch::Request.parameter_parsers = original_parsers
216 | @integration_session = old_session
217 | end
218 |
219 | def with_test_route_set
220 | with_routing do |set|
221 | set.draw do
222 | match '/', :to => 'web_service_test/test#assign_parameters', :via => :all
223 | end
224 | yield
225 | end
226 | end
227 | end
228 |
--------------------------------------------------------------------------------
/test/xml_params_parsing_test.rb:
--------------------------------------------------------------------------------
1 | require 'helper'
2 |
3 | class XmlParamsParsingTest < ActionDispatch::IntegrationTest
4 | class TestController < ActionController::Base
5 | class << self
6 | attr_accessor :last_request_parameters
7 | attr_accessor :last_request
8 | end
9 |
10 | def parse
11 | self.class.last_request_parameters = request.request_parameters
12 | self.class.last_request = request
13 | head :ok
14 | end
15 | end
16 |
17 | def teardown
18 | TestController.last_request_parameters = nil
19 | TestController.last_request = nil
20 | end
21 |
22 | def assert_parses(expected, xml)
23 | with_test_routing do
24 | post "/parse", params: xml, headers: default_headers
25 | assert_response :ok
26 | assert_equal(expected, TestController.last_request_parameters)
27 | end
28 | end
29 |
30 | test "nils are stripped from collections" do
31 | assert_parses(
32 | {"hash" => { "person" => []} },
33 | "")
34 |
35 | assert_parses(
36 | {"hash" => { "person" => ['foo']} },
37 | "foo\n")
38 | end
39 |
40 | test "parses hash params" do
41 | xml = "David"
42 | assert_parses({"person" => {"name" => "David"}}, xml)
43 | end
44 |
45 | test "parses single file" do
46 | xml = "David#{::Base64.encode64('ABC')}"
47 |
48 | person = ActionPack::XmlParser.call(xml)
49 |
50 | assert_equal "image/jpg", person['person']['avatar'].content_type
51 | assert_equal "me.jpg", person['person']['avatar'].original_filename
52 | assert_equal "ABC", person['person']['avatar'].read
53 | end
54 |
55 | test "logs error if parsing unsuccessful" do
56 | with_test_routing do
57 | output = StringIO.new
58 | xml = "David#{::Base64.encode64('ABC')}"
59 | post "/parse", params: xml, headers: default_headers.merge('action_dispatch.show_exceptions' => true, 'action_dispatch.logger' => ActiveSupport::Logger.new(output))
60 | assert_response :bad_request
61 | output.rewind && err = output.read
62 | assert err =~ /Error occurred while parsing request parameters/
63 | end
64 | end
65 |
66 | test "occurring a parse error if parsing unsuccessful" do
67 | with_test_routing do
68 | begin
69 | $stderr = StringIO.new # suppress the log
70 | xml = "David"
71 | exception = assert_raise(ActionDispatch::ParamsParser::ParseError) { post "/parse", xml, default_headers.merge('action_dispatch.show_exceptions' => false) }
72 | assert_equal REXML::ParseException, exception.original_exception.class
73 | assert_equal exception.original_exception.message, exception.message
74 | ensure
75 | $stderr = STDERR
76 | end
77 | end
78 | end
79 |
80 | test "parses multiple files" do
81 | xml = <<-end_body
82 |
83 | David
84 |
85 | #{::Base64.encode64('ABC')}
86 | #{::Base64.encode64('DEF')}
87 |
88 |
89 | end_body
90 |
91 | with_test_routing do
92 | post "/parse", params: xml, headers: default_headers
93 | assert_response :ok
94 | end
95 |
96 | person = TestController.last_request_parameters
97 |
98 | assert_equal "image/jpg", person['person']['avatars']['avatar'].first.content_type
99 | assert_equal "me.jpg", person['person']['avatars']['avatar'].first.original_filename
100 | assert_equal "ABC", person['person']['avatars']['avatar'].first.read
101 |
102 | assert_equal "image/gif", person['person']['avatars']['avatar'].last.content_type
103 | assert_equal "you.gif", person['person']['avatars']['avatar'].last.original_filename
104 | assert_equal "DEF", person['person']['avatars']['avatar'].last.read
105 | end
106 |
107 | test "rewinds body if it implements rewind" do
108 | xml = "Marie"
109 |
110 | with_test_routing do
111 | post "/parse", params: xml, headers: default_headers
112 | assert_equal TestController.last_request.body.read, xml
113 | end
114 | end
115 |
116 | private
117 | def with_test_routing
118 | with_routing do |set|
119 | set.draw do
120 | post 'parse', to: 'xml_params_parsing_test/test#parse'
121 | end
122 | yield
123 | end
124 | end
125 |
126 | def default_headers
127 | {'CONTENT_TYPE' => 'application/xml'}
128 | end
129 | end
130 |
131 | class RootLessXmlParamsParsingTest < ActionDispatch::IntegrationTest
132 | class TestController < ActionController::Base
133 | wrap_parameters :person, :format => :xml
134 |
135 | class << self
136 | attr_accessor :last_request_parameters
137 | end
138 |
139 | def parse
140 | self.class.last_request_parameters = request.request_parameters
141 | head :ok
142 | end
143 | end
144 |
145 | def teardown
146 | TestController.last_request_parameters = nil
147 | end
148 |
149 | test "parses hash params" do
150 | with_test_routing do
151 | xml = "David"
152 | post "/parse", params: xml, headers: {'CONTENT_TYPE' => 'application/xml'}
153 | assert_response :ok
154 | assert_equal({"name" => "David", "person" => {"name" => "David"}}, TestController.last_request_parameters)
155 | end
156 | end
157 |
158 | private
159 | def with_test_routing
160 | with_routing do |set|
161 | set.draw do
162 | post 'parse', to: 'root_less_xml_params__parsing_test/test#parse'
163 | end
164 | yield
165 | end
166 | end
167 | end
168 |
--------------------------------------------------------------------------------