Bing Translation Api access via SOAP interface from Ruby - ruby

I'm trying to use Bing Translator SOAP API (due to in HTTP API I'm getting 414 "Request too long" for not so big requests due to UTF-8 serialization).
So, I'm playing with bing_translator gem source trying to switch it from HTTP inerface to SOAP one using Savon SOAP toolkit.
My workflow as follows (access token getting function not shown):
WSDL_URI = 'http://api.microsofttranslator.com/V2/soap.svc?wsdl'
get_access_token
client = Savon.client(wsdl: WSDL_URI, headers: {'Authorization' => "Bearer #{#access_token['access_token']}"})
params = {
'from' => 'ru',
'to' => 'en',
'text' => 'Это текст для перевода',
'category' => 'general',
'contentType' => 'text/plain'
}
result = client.call(:translate, message: params)
Then SOAP request executes:
SOAP request: http://api.microsofttranslator.com/V2/soap.svc
Authorization: Bearer http%3a%2f%2fschemas.xmlsoap.org%2fws%2f2005%2f05%2fidentity%2fclaims%2fnameidentifier=invest_amurobl_ru&http%3a%2f%2fschemas.microsoft.com%2faccesscontrolservice%2f2010%2f07%2fclaims%2fidentityprovider=https%3a%2f%2fdatamarket.accesscontrol.windows.net%2f&Audience=http%3a%2f%2fapi.microsofttranslator.com&ExpiresOn=1381128612&Issuer=https%3a%2f%2fdatamarket.accesscontrol.windows.net%2f&HMACSHA256=Mw41PMMgw2n6ZVaGRXtwfR0vwMJUyIMltIyd9pa9MqA%3d
SOAPAction: "http://api.microsofttranslator.com/V2/LanguageService/Translate"
Content-Type: text/xml;charset=UTF-8
Content-Length: 454
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://tempuri.org/" xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Body>
<wsdl:Translate>
<to>en</to>
<text>Это текст для перевода</text>
<category>general</category>
<contentType>text/html</contentType>
<from>ru</from>
</wsdl:Translate>
</env:Body>
</env:Envelope>
And I'm getting error 500: Unhandled Service Exception
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang="en-US">Unhandled Service Exception</faultstring>
<detail>
<int xmlns="http://schemas.microsoft.com/2003/10/Serialization/">1</int>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
What's may be wrong? Can anyone who already using Bing Translator SOAP API to diff my soap-messages with yourself? Any advices to how to troubleshoot this.
Thanks for attention.
EDIT:
I've checked API with SoapUI, as #SteffenRoller advices and it works. Here is XML generated by SoapUI (values are inserted by hand):
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v2="http://api.microsofttranslator.com/V2">
<soapenv:Header/>
<soapenv:Body>
<v2:Translate>
<!--Optional:-->
<v2:text>Текст, который я хочу перевести</v2:text>
<!--Optional:-->
<v2:from>ru</v2:from>
<!--Optional:-->
<v2:to>en</v2:to>
<!--Optional:-->
<v2:contentType>text/plain</v2:contentType>
<!--Optional:-->
<v2:category>general</v2:category>
</v2:Translate>
</soapenv:Body>
</soapenv:Envelope>
As you can see the only difference is that all the tags inside a <Body> are in the v2 namespace. In the XML, generated by Savon this namespace isn't present at all.
So, now question is: How to instruct Savon to use correct namespace for tags inside the message body?
Although, I think, this is a Savon bug, I'll file it to developers, as SoapUI have generated correct XML by the same WSDL, and Savon doesn't.

Okay. This is a known bug: Savon issue #340. It's related to composite WSDL files and won't bi fixed in current major release :-(
So, in our case we need to tell Savon, what is our namespace is, what is it's name (just to align it with WSDL) and prepend each tag's name with this namespace.
The correct code looks like this:
require 'savon'
access_token = "http%3a%2f%2fschemas.xmlsoap.org%2fws...CA9TEs%3d"
client = Savon.client(
wsdl: 'http://api.microsofttranslator.com/V2/soap.svc?wsdl',
namespace: 'http://api.microsofttranslator.com/V2',
namespace_identifier: :v2,
headers: {'Authorization' => "Bearer #{access_token}"},
)
params = {
'v2:text' => 'Это текст для перевода',
'v2:from' => 'ru',
'v2:to' => 'en',
'v2:contentType' => 'text/plain',
'v2:category' => 'general',
}
result = client.call(:translate, message: params)
puts result.body[:translate_response][:translate_result]
Any advices and corrections are welcome. Thanks.

Related

How to make a SOAP call including namespace with Savon

I am trying to connect to this SOAP API. Specifically, I am trying to login via this login call.
The documentation states that I should make the following request:
POST /service/replicatorV4.asmx HTTP/1.1
Host: demo12231.srv106.webshopdemo.net
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://tempuri.org/Login"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<Login xmlns="http://tempuri.org/">
<username>string</username>
<password>string</password>
</Login>
</soap:Body>
</soap:Envelope>
When I in e.g. SoapUI makes the following request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/">
<soapenv:Header/>
<soapenv:Body>
<tem:Login>
<tem:username>Administrator</tem:username>
<tem:password>passw0rd12</tem:password>
</tem:Login>
</soapenv:Body>
</soapenv:Envelope>
then I get this satisfying response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<LoginResponse xmlns="http://tempuri.org/">
<LoginResult>48594fe6-41fd-45f9-9f84-89ef8c247b85</LoginResult>
</LoginResponse>
</soap:Body>
</soap:Envelope>
However, when I with Savon make a request like this:
require 'savon'
client = Savon.client( :wsdl => "http://demo12231.srv106.webshopdemo.net/service/replicatorV4.asmx?WSDL",
:open_timeout => 100,
:read_timeout => 100,
:ssl_verify_mode => :none,
:log_level => :debug,
:log => false,
:logger => Rails.logger,
:convert_request_keys_to => :camelcase)
response = client.call(:login, :message => {:username => "Administrator", :password => "passw0rd12"})
then I get this dissatisfying response:
#<Savon::Response:0x007ff78cfcc368
#globals=
#<Savon::GlobalOptions:0x007ff782fb8160
#option_type=:global,
#options=
{:encoding=>"UTF-8",
:soap_version=>1,
:namespaces=>{},
:logger=>
#<ActiveSupport::Logger:0x007ff78b136ea8
#default_formatter=
#<Logger::Formatter:0x007ff78b136e30 #datetime_format=nil>,
#formatter=
#<ActiveSupport::Logger::SimpleFormatter:0x007ff783e99f80
#datetime_format=nil>,
#level=0,
#logdev=
#<Logger::LogDevice:0x007ff78b136de0
#dev=
#<File:/Users/me/Projects/my_project/log/development.log>,
#filename=nil,
#mutex=
#<Logger::LogDevice::LogDeviceMutex:0x007ff78b136db8
#mon_count=0,
#mon_mutex=#<Mutex:0x007ff78b136d68>,
#mon_owner=nil>,
#shift_age=nil,
#shift_size=nil>,
#progname=nil>,
:log=>false,
:filters=>[],
:pretty_print_xml=>false,
:raise_errors=>true,
:strip_namespaces=>true,
:convert_response_tags_to=>
#<Proc:0x007ff782fc3e70#/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/savon-2.11.1/lib/savon/options.rb:85 (lambda)>,
:convert_attributes_to=>
#<Proc:0x007ff782fc3df8#/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/savon-2.11.1/lib/savon/options.rb:86 (lambda)>,
:multipart=>false,
:adapter=>nil,
:use_wsa_headers=>false,
:no_message_tag=>false,
:follow_redirects=>false,
:unwrap=>false,
:host=>nil,
:wsdl=>
"http://demo12231.srv106.webshopdemo.net/service/replicatorV4.asmx?WSDL",
:open_timeout=>100,
:read_timeout=>100,
:ssl_verify_mode=>:none,
:convert_request_keys_to=>:camelcase,
:endpoint=>
#<URI::HTTP:0x007ff78479cbf0 URL:http://demo12231.srv106.webshopdemo.net/service/replicatorV4.asmx>}>,
#http=
#<HTTPI::Response:0x007ff78cfcd2b8
#body=
"<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><LoginResponse xmlns=\"http://tempuri.org/\"><LoginResult xsi:nil=\"true\" /></LoginResponse></soap:Body></soap:Envelope>",
#code=200,
#headers=
{"Cache-Control"=>"private, max-age=0",
"Content-Type"=>"text/xml; charset=utf-8",
"Server"=>"Microsoft-IIS/8.5",
"Date"=>"Thu, 27 Aug 2015 05:29:42 GMT",
"Content-Length"=>"335"},
#raw_body=
"<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><LoginResponse xmlns=\"http://tempuri.org/\"><LoginResult xsi:nil=\"true\" /></LoginResponse></soap:Body></soap:Envelope>">,
#locals=
#<Savon::LocalOptions:0x007ff78ce7f550
#option_type=:local,
#options=
{:advanced_typecasting=>true,
:response_parser=>:nokogiri,
:multipart=>false,
:message=>{:username=>"Administrator", :password=>"passw0rd12"},
:soap_action=>"http://tempuri.org/Login"}>>
The body part of the response is:
{:login_response=>{:login_result=>nil, :#xmlns=>"http://tempuri.org/"}}
and this tells me that maybe the service did receive the overall request, but did not get the variables. The response looks a lot like the response when I in SoapUI make this request with wrong username and password:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<LoginResponse xmlns="http://tempuri.org/">
<LoginResult xsi:nil="true"/>
</LoginResponse>
</soap:Body>
</soap:Envelope>
I have noticed that the namespace tem is expected in variables. Could this have something to do with my issue? Or is there another explanation?
Create a pure Ruby script without Rails.
then check the output against what you've created with SoapUI. Post the differences and someone will be able to help.
when I run this script:
require 'savon'
c = Savon.client(wsdl:
"http://demo12231.srv106.webshopdemo.net/service/replicatorV4.asmx?WSDL",
log_level: :debug,
log: true,
pretty_print_xml: true)
response = c.call(:login,
:message => {:username => "Administrator", :password => "passw0rd12"})
it works for me. It might be something in your Rails part which interferes. I don't do Rails therefore I'll be of little help there (I prefer Sinatra :-)).

Creating Multiple Transactions based on Request

I'm mocking out a soap webservice and I can only get the default first response to return regardless of the request body.
I'm basing my attempts off the docs Multiple Transaction Examples and I'm confused as to what I'm doing wrong.
As an example:
+ Request
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="" xmlns:xsd="" xmlns:xsi="">
<SOAP-ENV:Body>
<m:transaction-identity-verification xmlns:m="">
</m:transaction-identity-verification>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
+ Response
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="">
<env:Header />
<env:Body>
<java:transaction-response xmlns:java="j">
<transaction-status>
<transaction-id>third_8020750179321</transaction-id>
<transaction-request-id>george_8020860578800</transaction-request-id>
<accounts-transaction-id>13</accounts-transaction-id>
<reference-id>13</reference-id>
<transaction-result>questions</transaction-result>
</transaction-status>
</java:transaction-response>
</env:Body>
</env:Envelope>
+ Request
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="" xmlns:xsd="" xmlns:xsi="">
<SOAP-ENV:Body>
<m:transaction-continue xmlns:m="">
</m:transaction-continue>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
+ Response
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="">
<env:Header/>
<env:Body>
<java:transaction-response xmlns:java="">
<transaction-status>
<transaction-id>cont_1_11020785803682</transaction-id>
<transaction-request-id>11020943348626</transaction-request-id>
<accounts-transaction-id>0</accounts-transaction-id>
<transaction-result>passed</transaction-result>
</transaction-status>
</java:transaction-response>
</env:Body>
</env:Envelope>
In the example above, I will only receive the first response even when I post two different requests. Based on the linked documentation this should be possible.
The Apiary mock-server does not have the capability to determine which response to return from multiple transaction examples based on the body of your request.
API Blueprint does allow you to provide multiple responses, Apiary mock server will only use response-code, headers or content-type to differentiate these examples.
For example, given two responses with different content-types:
+ Response 200 (plain/text)
Text Response
+ Response 200 (application/json)
{ "text": "JSON Response" }
Now, when we make a request to the mock server for the above responses. We can supply an Accept header to get the JSON response:
$ curl -H 'Accept: application/json' URL
{ "text": "JSON Response" }
Or ask for the text response:
$ curl -H 'Accept: plain/text' URL
Text Response
You can find more information regarding this at http://support.apiary.io/knowledgebase/articles/117119-handling-multiple-actions-on-a-single-resource

Savon 2 returns nothing in Rails 4

Here is my Savon 2
client = Savon::Client.new(wsdl: "http://www.webservicex.net/uszip.asmx?WSDL")
client.operations
response = client.call(:get_info_by_zip, :message => { us_zip: "90210" })
response.to_hash
And response is:
{:get_info_by_zip_response=>{:#xmlns=>"http://www.webserviceX.NET"}}
In the SoapUI:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET">
<soapenv:Header/>
<soapenv:Body>
<web:GetInfoByZIP>
<!--Optional:-->
<web:USZip>90210</web:USZip>
</web:GetInfoByZIP>
</soapenv:Body>
</soapenv:Envelope>
I get this response:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetInfoByZIPResponse xmlns="http://www.webserviceX.NET">
<GetInfoByZIPResult>
<NewDataSet xmlns="">
<Table>
<CITY>Beverly Hills</CITY>
<STATE>CA</STATE>
<ZIP>90210</ZIP>
<AREA_CODE>310</AREA_CODE>
<TIME_ZONE>P</TIME_ZONE>
</Table>
</NewDataSet>
</GetInfoByZIPResult>
</GetInfoByZIPResponse>
</soap:Body>
</soap:Envelope>
For the life of me I cant figure it out. Can someone please have a look and let me know what am I doing wrong?
Thanks
Your tag within the message seems wrong, instead us_zip you should use "USZip" (in quotes!).
This works for me:
#!ruby
require 'savon'
require 'pp'
WSDL_URL = 'http://www.webservicex.net/uszip.asmx?wsdl'
client = Savon.client(
wsdl: WSDL_URL,
log: true, # set true to switch on logging
log_level: :debug,
pretty_print_xml: true
)
zip = ARGV[0] || "98052"
response = client.call(:get_info_by_zip,
message: { "USZip" => zip }
)
pp response.to_hash

Savon - SOAP - ruby - 400 Bad Request

I'm trying to use Savon to make a SOAP request with Ruby, but I'm receiving a 400 Bad Request response from the server.
This is the request I'm trying to make (according to soapUI):
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:apis="http://www.csisoftwareusa.com/ApiService">
<soap:Header/>
<soap:Body>
<apis:AuthenticateConsumer>
<!--Optional:-->
<apis:consumerName>?</apis:consumerName>
<!--Optional:-->
<apis:consumerPassword>?</apis:consumerPassword>
</apis:AuthenticateConsumer>
</soap:Body>
</soap:Envelope>
Here is the request that I make with Ruby; it returns a 400 Bad Request error:
<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<ins0:AuthenticateConsumer>
<ins0:consumerName>?</ins0:consumerName>
<ins0:consumerPassword>?</ins0:consumerPassword>
</ins0:AuthenticateConsumer>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Http Headers: SOAPAction: "http://www.csisoftwareusa.com/ApiService/AuthenticateConsumer", Content-Type: text/xml;charset=UTF-8, Content-Length: 504
Here is the request that I was able to make with Python. THIS request succeeds:
<SOAP-ENV:Envelope>
<SOAP-ENV:Header/>
<ns0:Body>
<ns1:AuthenticateConsumer>
<ns1:consumerName>?</ns1:consumerName>
<ns1:consumerPassword>?</ns1:consumerPassword>
</ns1:AuthenticateConsumer>
</ns0:Body>
</SOAP-ENV:Envelope>
Http headers: {'SOAPAction': u'"http://www.csisoftwareusa.com/ApiService/AuthenticateConsumer"', 'Content-Type': 'text/xml; charset=utf-8'}
I need to integrate calls to this API into a Rails application, so doing it in Python isn't a valid solution.
I'm wondering if anyone can see what I'm missing. Is the empty <SOAP-ENV:Header /> tag the issue, and if so, how can I add that to the Savon request?
Thanks,
Stuart
In my case, I had repeated namespaces, so I was getting 400 Bad Request.
My code:
require 'savon'
namespaces = {
"xmlns:soap": "http://schemas.xmlsoap.org/soap/envelope/",
"xmlns:xsi": "http://www.w3.org/2001/XMLSchema-instance",
"xmlns:xsd": "http://www.w3.org/2001/XMLSchema",
}
client = Savon.client(
...
:namespace => namespaces
}
I removed the :namespace option and the error was gone.
How did I find the error?
Use build_request instead of call and print the request body:
client.build_request(:search, message: {...})
puts request.body
I took the request body and pasted it into SoapUI, then I made changes one by one until the request was successful.
The issue here is with my http headers: Because the url has spaces in it, the url has to be encoded. However, I have to encode it before passing it to Savon, which then encodes it again - this double-encoded url fails. See: https://stackoverflow.com/questions/14482251/ruby-savon-soap-request-double-escapes-spaces-in-url
Thanks,
Stuart

Ruby: Savon SOAP Requests receives 400 and 415 errors

I am trying to make a SOAP request using the ruby library Savon.
I am using the following code:
require "savon"
Savon.configure do |config|
config.soap_version = 2 # use SOAP 1.2
config.raise_errors = false
end
wsdl_logon = Savon::Client.new do
wsdl.document = "https://api.affili.net/V2.0/Logon.svc?wsdl"
end
username = 'XXX'
password = 'YYY'
wsdl_logon.http.headers["Content-Type"] = "text/xml; charset=utf-8"
response = wsdl_logon.request "Logon" do
soap.body = {'Username' => username, 'Password' => password, 'WebServiceType' => 'Product'}
end
if response.http_error?
puts "Http Error!"
puts y response.http_error
else
puts "No Http Error!"
end
But I keep receiving 400 error messages ("bad request"). Or, if I remove the following line
wsdl_logon.http.headers["Content-Type"] = "text/xml; charset=utf-8"
I am receiving 415 error messages ("unsupported media type").
I have been using PHP to make these requests until now, and the following code always worked without problems:
$soap_logon = new SoapClient('https://api.affili.net/V2.0/Logon.svc?wsdl');
$token = $soap_logon->Logon(array(
'Username' => 'XXX',
'Password' => 'YYY',
'WebServiceType' => 'Product'
));
Can anybody point me to the right direction what a possible error source might be? I am completely lost right now.
Thank you for your help.
I did as Tom De Leu suggested, and tried to remove as many differences in the generated SOAP requests in question as possible. But I still keep receiving 400 errors. Any hint on possible reasons for this would be highly appreciated.
This is the (working) Request generated by PHP (linebreaks in XML added for clarity):
POST /V2.0/Logon.svc HTTP/1.1
Host: api.affili.net
Connection: Keep-Alive
User-Agent: PHP-SOAP/5.2.0-8+etch16
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://affilinet.framework.webservices/Svc/ServiceContract1/Logon"
Content-Length: 456
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://affilinet.framework.webservices/types"
xmlns:ns2="http://affilinet.framework.webservices/Svc"
>
<SOAP-ENV:Body>
<ns2:LogonRequestMsg>
<ns1:Username>xxx</ns1:Username>
<ns1:Password>yyy</ns1:Password>
<ns1:WebServiceType>Product</ns1:WebServiceType>
</ns2:LogonRequestMsg>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
This is the (not working) request generated by Ruby (again, xml linebreaks added for clarity)
SOAP request: https://api.affili.net/V2.0/Logon.svc
Content-Type: text/xml; charset=utf-8, SOAPAction: http://affilinet.framework.webservices/Svc/ServiceContract1/Logon, Content-Length: 605
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="http://affilinet.framework.webservices/Svc"
SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:ns1="http://affilinet.framework.webservices/types"
xmlns:ns2="http://affilinet.framework.webservices/Svc"
>
<SOAP-ENV:Body>
<ns2:LogonRequestMsg>
<ns1:Username>XXX</ns1:Username>
<ns1:Password>YYY</ns1:Password>
<wsdl:WebServiceType>Product</wsdl:WebServiceType>
</ns2:LogonRequestMsg>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
HTTPI executes HTTP POST using the httpclient adapter
SOAP response (status 400):
I found that I needed to add the headers in to get past the 415 error.
Savon.client(wsdl: "www.sample_doman.com/endpoint?wsdl", headers: {'Content-Type' => 'application/soap+xml; charset=utf-8'})
I would suggest looking at the XML sent by the PHP code, then comparing it with the XML sent by the Ruby Savon code, and check where the differences are. Then see whether you can modify your ruby code to generate the correct request.
Telling Savon to use SOAP version 2 (really 1.2) and then manually setting the content type to text/xml kind of defeats the purpose.
If your web service requires SOAP 1.2, then it is expecting a content type of 'application/soap+xml', which SAVON will do for you if you set the soap_version to 2.
If you want a content type of text/xml, just set your soap_version config variable to 1

Resources