GET method with json body - ruby-on-rails

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

Related

JSON Rest-Client Authorization in 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.

Withings API: The callback URL is either unknown or invalid

I'm trying to set a notification in the withings API (with the withings-simplificator gem). I always get this error, no matter what URL I enter or if I encode it or not:
irb(main):013:0> user.subscribe_notification('http://foo.bar.com', 'test subscription')
Withings::ApiError: The callback URL 'http://foo.bar.com' is either unknown or invalid - Status code: 293
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/connection.rb:80:in `verify_response!'
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/connection.rb:22:in `get_request'
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/connection.rb:27:in `get_request'
from /app/vendor/bundle/ruby/2.2.0/gems/simplificator-withings-0.7.0/lib/withings/user.rb:26:in `subscribe_notification'
from (irb):13
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/console.rb:110:in `start'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/console.rb:9:in `start'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:68:in `console'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands/commands_tasks.rb:39:in `run_command!'
from /app/vendor/bundle/ruby/2.2.0/gems/railties-4.2.4/lib/rails/commands.rb:17:in `<top (required)>'
from bin/rails:8:in `require'
from bin/rails:8:in `<main>'
Has anyone encountered this and has a solution?
Update 1:
So I tried without the withings simplificator gem:
API_KEY = '123'
API_SECRET = '456'
USER_ID = '789'
USER_KEY = 'abc'
USER_SECRET = 'def'
CONFIGURATION = { site: 'https://oauth.withings.com',
request_token_path: '/account/request_token',
access_token_path: '/account/access_token',
authorize_path: '/account/authorize',
http_method: :get,
scheme: :query_string
}
#consumer = OAuth::Consumer.new API_KEY, API_SECRET, CONFIGURATION
#access_token = OAuth::AccessToken.new #consumer, USER_KEY, USER_SECRET
url = ERB::Util.url_encode("www.foo.bar/trigger")
comment = ERB::Util.url_encode("Trigger")
response = #access_token.get("https://wbsapi.withings.net/notify?action=subscribe&userid=#{USER_ID}&callbackurl=#{url}&comment=#{comment}")
JSON.parse(response.body)
And same error:
irb(main):051:0> JSON.parse(response.body)
=> {"status"=>293}
What am I doing wrong?
You have to make sure during setup
your "trigger url" exists
it responds with "ok" to a POST
it is fast ... I couldn't figure this out exactly how fast, but I think the response time should be < 1 second
With an environment like this, my code above works.
Your notification endpoint going to do two operations:
it is going to respond test request response (while you register it will check your URL is exist or not). You will receive call with empty body object. If it is not have userid, it is not a data notification, so you have to respond status as 200 with empty body;
after successful registration you will receive data alert. This time you can handle by your business logic.

Multipule posts in loop with FbGraph gives: OAuthException :: (#1) An error occured while creating the share

I'm having an issue posting posts to a page, and only get the helpful error:
OAuthException :: (#1) An error occured while creating the share
The first 20 or so posts worked great, then it started to error.
Does facebook have a limit on the number of posts one can make to a page (spam) or something?
I can reproduce form rails c and I have triple checked my access_token and can manually post from FB directly.
(I'm using the page access_token not my user one)
I opened a issue on FbGraph's githup but nov seems to think its a FB issue.
My Code:
admin = Admin.first
page = FbGraph::Page.new(admin.facebook_page_id)
Story.where(:facebook_post_id => nil).all.each do |story|
post = page.feed!(
:link => 'http://www.example.com/stories/'+story.cached_slug,
:access_token => admin.facebook_page_access_token
)
story.facebook_post_id = post.identifier
story.live = true
story.save
sleep 1
end
Backtrace:
FbGraph::InvalidRequest: OAuthException :: (#1) An error occured while creating the share
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/exception.rb:47:in `block in handle_httpclient_error'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/exception.rb:44:in `each'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/exception.rb:44:in `handle_httpclient_error'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/node.rb:142:in `handle_response'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/node.rb:55:in `post'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/fb_graph-2.6.4/lib/fb_graph/connections/feed.rb:14:in `feed!'
from (irb):9:in `block in irb_binding'
from (irb):5:in `each'
from (irb):5
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.12/lib/rails/commands/console.rb:47:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.12/lib/rails/commands/console.rb:8:in `start'
from /usr/local/rvm/gems/ruby-1.9.3-p392/gems/railties-3.2.12/lib/rails/commands.rb:41:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
Update:
It looks like my access_token was banned for 24 hours.
I was just able to add another 28 posts to the page before getting this error again. I tried with a 10sec sleep this time but still got banned... I guess I will try with a 60sec sleep tomorrow.. :(
I was not able to fix this problem but I have worked around it.
By uploading 1 post every 3 minutes I was able to get 200-300 posts up a day.
admin = Admin.first
page = FbGraph::Page.new(admin.facebook_page_id)
Story.where(:facebook_post_id => nil).all.each do |story|
post = page.feed!(
:link => 'http://www.example.com/stories/'+story.cached_slug,
:access_token => admin.facebook_page_access_token
)
story.facebook_post_id = post.identifier
story.live = true
story.save
sleep 180
end
I hope this helps someone else with this problem.

Ruby Newbie strftime Time.Now

I have the following written in ruby
t = Time.now
t.strftime("%Y-%d-%m")
SCHEDULER.every '1m', :first_in => 0 do |job|
send_event('gmail_gh', {current: gmail.inbox.count(:after => Date.parse(t)), older: gmail.inbox.count})
But i get this error
scheduler caught exception:
can't convert Time into String
/var/dashing/cdmdash/jobs/gmail_gh.rb:21:in `parse'
/var/dashing/cdmdash/jobs/gmail_gh.rb:21:in `block in <top (required)>'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/jobs.rb:231:in `call'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/jobs.rb:231:in `trigger_block'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/jobs.rb:191:in `block in trigger'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/scheduler.rb:416:in `call'
/usr/local/rvm/gems/ruby-1.9.3-p327/gems/rufus-scheduler-2.0.17/lib/rufus/sc/scheduler.rb:416:in `block in trigger_job'
I think it has something to do with the t variable and it not being a truing, I am new to Ruby so I am abit stuck
If you look at the gem documentation, you will see that the :after and :before params take in a date in the format of YYYY-MM-DD.
From the gem Readme:
gmail.inbox.count(:after => Date.parse("2010-02-20"), :before => Date.parse("2010-03-20"))
gmail.inbox.count(:on => Date.parse("2010-04-15"))
Your code is passing in YYYY-DD-MM which is likely causing the error.
Edit
When you call strftime on a datetime object, it doesn't modify the object - only returns the string notation based on format you give.
As a result, the Date.parse(t) is still getting Time.now was a parameter.
Try this:
t = Time.now.strftime("%Y-%m-%d")
Date.parse(t)

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