JSON Rest-Client Authorization in Rails - ruby-on-rails

For some reason when I run this in my Rails console it is not working.
RestClient.post 'http://localhost/WebService/AuthenticateLogin', :content_type => :json, {:params => {:RuntimeEnvironment => 1, 'Email' => 'someone#example.com', 'Password' => 'Pa$$worD'}}
The odd part is when I do the same with cURL it works perfectly fine:
curl -H "Content-Type: application/json" -d '{"RuntimeEnvironment":1,"Email":"someone#example.com","Password":"Pa$$worD"}' -X POST http://localhost/WebService/AuthenticateLogin
Here is my stacktrace:
SyntaxError: (irb):33: syntax error, unexpected '\n', expecting =>
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands/console.rb:9:in `start'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:68:in `console'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:39:in `run_command!
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
And because I think it may be relevant, I used this statement as well:
RestClient.post 'http://localhost/WebService/AuthenticateLogin', :content_type => :json, :params => {:RuntimeEnvironment => 1, 'Email' => 'someone#example.com', 'Password' => 'Pa$$worD'}
And got this as my stacktrace:
RestClient.post "http://localhost/WebService/AuthenticateLogin", "content_type=json&params[RuntimeEnvironment]=1&params[Email]=someone%40example.com&params[Password]=Pa$$worD", "Accept"=>"*/*; q=0.5, application/
xml", "Accept-Encoding"=>"gzip, deflate", "Content-Length"=>"114", "Content-Type"=>"application/x-www-form-urlencoded"
# => 400 BadRequest | text/html 2738 bytes
RestClient::BadRequest: 400 Bad Request
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rest-client-1.6.7/lib/restclient/abstract_response.rb:48:in `return!'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rest-client-1.6.7/lib/restclient/request.rb:230:in `process_result'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rest-client-1.6.7/lib/restclient/request.rb:178:in `block in transmit'
from C:/Ruby200-x64/lib/ruby/2.0.0/net/http.rb:852:in `start'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rest-client-1.6.7/lib/restclient/request.rb:172:in `transmit'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rest-client-1.6.7/lib/restclient/request.rb:64:in `execute'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rest-client-1.6.7/lib/restclient/request.rb:33:in `execute'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/rest-client-1.6.7/lib/restclient.rb:72:in `post'
from (irb):34
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands/console.rb:110:in `start'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands/console.rb:9:in `start'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:68:in `console'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from C:/Ruby200-x64/lib/ruby/gems/2.0.0/gems/railties-4.2.0/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
I have scoured Stack and tried different ways of listing out the params, moving/removing the content_type, etc. Nothing is working for me.

You don't need to nest the params like that. Just do:
RestClient.post 'http://localhost/WebService/AuthenticateLogin', {"RuntimeEnvironment" => 1, 'Email' => 'someone#example.com', 'Password' => 'Pa$$worD'}, :content_type => :json

I noticed my content_type was not being updated, searched it up and StackOverflow came through for me.
How do I make Ruby's RestClient gem respect content_type on post?
I basically just changed my request to be:
RestClient.post 'http://localhost/WebService/AuthenticateLogin', '{"RuntimeEnvironment":1, "Email":"someone#example.com", "Password":"Pa$$worD"}', :content_type => "json"
I merely added quotes around my params like so: '{params}'
And instead of using => in the params, I changed to colons just like the actual request I used in cURL and everything worked like a charm.
Also note I quoted the "json" content_type.
Thanks #rlarcombe for your help.

Related

Savon::SoapFault: Unexpected character '>' (code 62) (expected a name start character)

I am trying to understand the Railscast: SOAP with Savon and implement it for my scenario.
I have executed the following in rails console
realm = Base64.strict_encode64("user:password")
client = Savon.client(wsdl: "http://xxxxx?wsdl", soap_header: { 'Authorization:' => "Basic #{realm}"}, log: true, log_level: :debug, pretty_print_xml: true)
message = {"X1" => "XX", "X2" => 108539, "X3" => 2, "CONFIRM" => TRUE}
All fine so far. The following line is throwing an error
response = client.call(:update_job, message: message)
Please can you let me know how to resolve the following error or any useful documentation that I can look at to fix the error. (I have tried searching online and also looked at http://savonrb.com/version2/requests.html)
HTTPI POST request to sit (net_http)
SOAP response (status 500)
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd=
"http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-i
nstance">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>Unexpected character '>' (code 62) (expected a name start
character)
at [row,col {unknown-source}]: [1,434]</faultstring>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Savon::SOAPFault: (soap:Server) Unexpected character '>' (code 62) (expected a n
ame start character)
at [row,col {unknown-source}]: [1,434]
from c:/jruby-1.7.12/lib/ruby/gems/shared/gems/savon-2.6.0/lib/savon/res
ponse.rb:85:in `raise_soap_and_http_errors!'
from c:/jruby-1.7.12/lib/ruby/gems/shared/gems/savon-2.6.0/lib/savon/res
ponse.rb:14:in `initialize'
from c:/jruby-1.7.12/lib/ruby/gems/shared/gems/savon-2.6.0/lib/savon/ope
ration.rb:64:in `create_response'
from c:/jruby-1.7.12/lib/ruby/gems/shared/gems/savon-2.6.0/lib/savon/ope
ration.rb:55:in `call'
from c:/jruby-1.7.12/lib/ruby/gems/shared/gems/savon-2.6.0/lib/savon/cli
ent.rb:36:in `call'
from (irb):75:in `evaluate'
from org/jruby/RubyKernel.java:1101:in `eval'
from org/jruby/RubyKernel.java:1501:in `loop'
from org/jruby/RubyKernel.java:1264:in `catch'
from org/jruby/RubyKernel.java:1264:in `catch'
from c:/jruby-1.7.12/lib/ruby/gems/shared/gems/railties-3.2.13/lib/rails
/commands/console.rb:47:in `start'
from c:/jruby-1.7.12/lib/ruby/gems/shared/gems/railties-3.2.13/lib/rails
/commands/console.rb:8:in `start'
from c:/jruby-1.7.12/lib/ruby/gems/shared/gems/railties-3.2.13/lib/rails
/commands.rb:41:in `(root)'
from org/jruby/RubyKernel.java:1065:in `require'
from script/rails:6:in `(root)'
Thanks.
Your soap_header should not be postfixed with : (Authorization:).
client = Savon.client(
wsdl: "http://xxxxx?wsdl",
soap_header: { 'Authorization' => "Basic #{realm }"},
log: true,
log_level: :debug,
pretty_print_xml: true
)
http://savonrb.com/version2/globals.html

GET method with json body

I have to consume methods from an external API provided, and one method is a GET with a json body. I'm making the connection through rails using rest-client gem that makes that job.
I know that RestClient.post accepts json:
RestClient.post "http://example.com/resource", { 'x' => 1 }.to_json, :content_type => :json, :accept => :json
And also for my case works perfectly. But if i change the .post to .get, i get this error:
ArgumentError: wrong number of arguments (3 for 2)
from /Users/toptierlabs/.rvm/gems/ruby-1.9.3-p429#rails3tutorial2ndEd/gems/rest-client-1.6.7/lib/restclient.rb:67:in `get'
from /Users/toptierlabs/Desktop/Proyectos/AppraisalLane/app/models/autoniq.rb:8:in `getCircleInventory'
from (irb):3
from /Users/toptierlabs/.rvm/gems/ruby-1.9.3-p429#rails3tutorial2ndEd/gems/railties-4.0.2/lib/rails/commands/console.rb:90:in `start'
from /Users/toptierlabs/.rvm/gems/ruby-1.9.3-p429#rails3tutorial2ndEd/gems/railties-4.0.2/lib/rails/commands/console.rb:9:in `start'
from /Users/toptierlabs/.rvm/gems/ruby-1.9.3-p429#rails3tutorial2ndEd/gems/railties-4.0.2/lib/rails/commands.rb:62:in `<top (required)>'
from bin/rails:4:in `require'
from bin/rails:4:in `<main>'
Is there any way in Rails to do a GET with a json body? Or any possible solution to translate a "get with a json body" to something else? Is not necessary to use the rest-client gem, if any one have another solution is welcome too.
Thanks!
Solved:
RestClient.get "http://example.com/resource", params: {'json' => { 'x' => 1 }.to_json},:content_type => :json, :accept => :json

Encoding::UndefinedConversionError: "\xA8" from ASCII-8BIT to UTF-8 (SFTP)

Using the Net-SFTP gem, Ruby 2 and Rails 4
I wrote code that was working in pure ruby, but copied my code over to rails and now I get:
Encoding::UndefinedConversionError: "\xA8" from ASCII-8BIT to UTF-8
What can I change in my code to get this working?
def self.get_recent_file(ftp_file, local_file)
Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
sftp.download!(ftp_file, local_file)
end
end
Log
Encoding::UndefinedConversionError: "\xA8" from ASCII-8BIT to UTF-8
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/operations/download.rb:339:in `write'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/operations/download.rb:339:in `write'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/operations/download.rb:339:in `on_read'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/request.rb:87:in `call'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/request.rb:87:in `respond_to'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:948:in `dispatch_request'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:911:in `when_channel_polled'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/channel.rb:311:in `call'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/channel.rb:311:in `process'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `block in preprocess'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `each'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `preprocess'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:205:in `process'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `block in loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
... 13 levels...
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:222:in `preprocess'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:205:in `process'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `block in loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-ssh-2.8.0/lib/net/ssh/connection/session.rb:169:in `loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:802:in `loop'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp/session.rb:787:in `connect!'
from /usr/local/opt/rbenv/versions/2.1.0-rc1/lib/ruby/gems/2.1.0/gems/net-sftp-2.1.2/lib/net/sftp.rb:32:in `start'
Code referenced in log from GEM:
https://github.com/net-ssh/net-sftp/blob/master/lib/net/sftp/operations/download.rb#L339
# Called when a read from a file finishes. If the read was successful
# and returned data, this will call #download_next_chunk to read the
# next bit from the file. Otherwise the file will be closed.
def on_read(response)
entry = response.request[:entry]
if response.eof?
update_progress(:close, entry)
entry.sink.close
request = sftp.close(entry.handle, &method(:on_close))
request[:entry] = entry
elsif !response.ok?
raise "read #{entry.remote}: #{response}"
else
entry.offset += response[:data].bytesize
update_progress(:get, entry, response.request[:offset], response[:data])
entry.sink.write(response[:data]) # <~~ Line#339
download_next_chunk(entry)
end
end
This helps me:
def self.get_recent_file(ftp_file, local_file)
local_io = File.new(local_file, mode: 'w', encoding: 'ASCII-8BIT')
Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
sftp.download!(ftp_file, local_io)
end
local_io.close
end
A combination of user72136's answer and the answer to this question worked for me (my remote file wasn't even ASCII):
def self.get_recent_file(ftp_file, local_file)
local_io = File.new(local_file, mode: 'wb')
Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
sftp.download!(ftp_file, local_io)
end
local_io.close
end
As line#339 is showing
entry.sink.write(response[:data])
Fix it as :
entry.sink.write(response[:data].force_encoding('ASCII-8BIT').encode('UTF-8'))
Change the line -
sftp.download!(ftp_file, local_file)
to say
sftp.download!(ftp_file, local_file).to_s.encode('UTF-8', {:invalid => :replace, :undef => :replace, :replace => '?'})
This problem is being produced by how Ruby opens text-files by default after Ruby 2.0 version with UTF-8 encoding. Where you open your file you can put:
local_file = Tempfile.new(encoding: 'ascii-8bit')
#or another thing to do is to switch to binary-mode
local_file = Tempfile.new
local_file.binmode
You can also open a binary-file like this:
local_file = File.open('/tmp/local_file', 'wb')
Another solution you can do is to pass to the gem-code the filepath, instead of an open file:
def self.get_recent_file(ftp_file, local_file)
Net::SFTP.start(Config::A_FTP[:domain], Config::A_FTP[:username], :password => Config::A_FTP[:password]) do |sftp|
sftp.download!(ftp_file, local_file.path)
end
end

OAuth::Unauthorized: 401 using dropbox-api gem in Rails 3.2 console

I am trying to authorize using dropbox-api gem just in the Rails console
Here's how I fired it up in the console:
But I keep on getting 401 Unauthorized error upon accessing via oauth_verifier
Here's the gem that I am using: https://github.com/futuresimple/dropbox-api
> Dropbox::API::Config.app_key = MY_APP_TOKEN
> Dropbox::API::Config.app_secret = MY_APP_SECRET
> consumer = Dropbox::API::OAuth.consumer(:authorize)
> request_token = consumer.get_request_token
> request_token.authorize_url(:oauth_callback => 'http://localhost:3000/callback/dropbox')
> hash = { oauth_token: request_token.token, oauth_token_secret: request_token.secret}
> request_token = OAuth::RequestToken.from_hash(consumer, hash)
> result = request_token.get_access_token(:oauth_verifier => request_token.token)
ERROR:
1.9.3-p448 :019 > access_token = request_token.get_access_token(:oauth_verifier => request_token.token)
OAuth::Unauthorized: 401 Unauthorized
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/oauth-0.4.7/lib/oauth/consumer.rb:216:in `token_request'
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/oauth-0.4.7/lib/oauth/tokens/request_token.rb:18:in `get_access_token'
from (irb):19
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.13/lib/rails/commands/console.rb:47:in `start'
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.13/lib/rails/commands/console.rb:8:in `start'
from /Users/xiruki/.rvm/gems/ruby-1.9.3-p448/gems/railties-3.2.13/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Any workarounds will be appreciated.
Moving my comment to an answer:
Be sure to actually visit the authorize URL and "allow" the app before trying to call get_access_token.

Nokogiri XML Builder error -> "Document already has a root node"

In my code I'm building an XML request. However, this simple fragment generates an error:
def create_gateways_request
#request_xml = Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
xml.gateways(:ua => "#{#plugin_name} #{#version}") {
xml.merchant {
xml.account MSP['merchant']['account_id']
xml.site_id MSP['merchant']['site_id']
xml.site_secure_code MSP['merchant']['site_code']
}
xml.customer {
xml.country #customer[:country]
}
}
end
#request_xml.to_xml
end
The error:
RuntimeError: Document already has a root node
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/nokogiri-1.5.2/lib/nokogiri/xml/document.rb:212:in `add_child'
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/nokogiri-1.5.2/lib/nokogiri/xml/node.rb:549:in `parent='
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/nokogiri-1.5.2/lib/nokogiri/xml/builder.rb:371:in `insert'
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/nokogiri-1.5.2/lib/nokogiri/xml/builder.rb:363:in `method_missing'
from (irb):146
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.1.3/lib/rails/commands/console.rb:45:in `start'
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.1.3/lib/rails/commands/console.rb:8:in `start'
from /Users/scriptdude/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.1.3/lib/rails/commands.rb:40:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
The root node is <gateways>, right?
What am I doing wrong here?
I cannot reproduce this locally, but you might try this at the end of your method instead:
#request_xml.doc.to_xml
It appears that it thought that you were trying to add a new <to_xml> node to the root of the document, and is complaining because you already have a <gateways> element at the root. I cannot fathom why Nokogiri 1.5.2 would do this, however, as Builder does have a to_xml method.
Here's my simple test that works for me:
require "nokogiri"
def do_it
#builder = Nokogiri::XML::Builder.new{ |x| x.root{ x.kid } }
#builder.to_xml
end
puts do_it
#=> <?xml version="1.0"?>
#=> <root>
#=> <kid/>
#=> </root>
p Nokogiri::VERSION
#=> "1.5.2"

Resources