How can I get HTTParty to recognize ":footer" and ":collector" parameters? - ruby

I received the following code from a development team:
curl -u EMAILADDRESS:PASSWORD -d "sender=NAME <EMAILADDRESS>&message=[Invite Link]&collector=COLLECTOR&subject=Test Invite&footer=My Custom Text [Unsubscription Link]"
I have been told that the above works fine. This is what I translated it to in Ruby 1.9.3, using the httparty gem:
call= "/api/v2/emails/?survey=#{i}"
puts collector_final_id
url= HTTParty.post("https://www.fluidsurveys.com#{call}",
:basic_auth => auth,
:headers => { 'Content-Type' => 'application/x-www-form-urlencoded','Accept' => 'application/x-www-form-urlencoded' },
:collector => collector,
:body => {
"subject" => "Test Invite",
"sender" => "NAME <EMAILADDRESS>",
"message" => "[Invite Link]"
},
:footer => "My Custom Text [Unsubscription Link]"
)
Everything within this works fine except for the :footer and :collector parameters. It doesn't seem to recognize them at all.
There are no errors thrown, they just aren't included in the actual email I am sending. What am I doing wrong when passing in those two parameters?

Your :collector and :footer are not correct.
I wrote a little Sinatra service to receive a POST request with any parameters:
require 'pp'
require 'sinatra'
post "/*" do
pp params
end
And ran it, launching the web-server on my Mac OS laptop. As Sinatra apps do, it resides at 0.0.0.0:4567.
Running this code:
require 'httparty'
url = HTTParty.post(
"http://localhost:4567/api/v2/emails?survey=1",
:headers => {
'Content-Type' => 'application/x-www-form-urlencoded',
'Accept' => 'application/x-www-form-urlencoded'
},
:body => {
"subject" => 'subject',
"sender" => 'sender',
"message" => 'message',
},
:collector => 'collector',
:footer => 'footer'
)
puts url
Outputs:
["survey", "1"]["subject", "subject"]["sender", "sender"]["message", "message"]["splat", ["api/v2/emails"]]["captures", ["api/v2/emails"]]
Sinatra said:
127.0.0.1 - - [11/Sep/2013 17:58:47] "POST /api/v2/emails?survey=1 HTTP/1.1" 200 - 0.0163
{"survey"=>"1",
"subject"=>"subject",
"sender"=>"sender",
"message"=>"message",
"splat"=>["api/v2/emails"],
"captures"=>["api/v2/emails"]}
Changing :collector and :footer to strings and moving them inside the body, where they should be:
require 'httparty'
url = HTTParty.post(
"http://localhost:4567/api/v2/emails?survey=1",
:headers => {
'Content-Type' => 'application/x-www-form-urlencoded',
'Accept' => 'application/x-www-form-urlencoded'
},
:body => {
"subject" => 'subject',
"sender" => 'sender',
"message" => 'message',
'collector' => 'collector',
'footer' => 'footer'
},
)
puts url
Outputs:
["survey", "1"]["subject", "subject"]["sender", "sender"]["message", "message"]["collector", "collector"]["footer", "footer"]["splat", ["api/v2/emails"]]["captures", ["api/v2/emails"]]
And Sinatra said:
127.0.0.1 - - [11/Sep/2013 18:04:13] "POST /api/v2/emails?survey=1 HTTP/1.1" 200 - 0.0010
{"survey"=>"1",
"subject"=>"subject",
"sender"=>"sender",
"message"=>"message",
"collector"=>"collector",
"footer"=>"footer",
"splat"=>["api/v2/emails"],
"captures"=>["api/v2/emails"]}
The problem is, the POST request ONLY uses a URL and a :body hash. Inside the :body hash go all the variables you're sending to the server. That's why the second version of the code, with 'collector' and 'footer' works.

There is no comma after your :body parameter

Related

POST JSON data with Curl Multi from ruby

I am using the curb gem to do a Curl Multi post using JSON data. However I am unable to actually get the parameters to get posted and have been unable to figure out how to properly configure the parameters.
urls = [
{
:url => "http://localhost:5000/",
:method => :post,
:headers => {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
:post_fields => {'field1' => 'value1', 'k' => 'j'}
}
]
Curl::Multi.http(urls) do |easy, code, method|
puts "#{easy.body_str.inspect}, #{method.inspect}, #{code.inspect}"
end
=>
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n<title>400 Bad Request</title>\n<h1>Bad Request</h1>\n<p>The browser (or proxy) sent a request that this server could not understand.</p>\n", :post, nil
Do that:
urls = [
{
:url => "http://localhost:5000/",
:method => :post,
:headers => {'Accept' => 'application/json', 'Content-Type' => 'application/json'},
:post_fields => {},
:post_body => {'field1' => 'value1', 'k' => 'j'}.to_json,
}
]
The problem: curb doesn't know that you are sending a JSON data. Curb don't read and interprets the contents of :headers. As you can see here, curb transforms your hash into a string separated by "&", which is the default for a normal (non-json) http data sending (eg.: "field1=value1&k=j"). When the server (Rails) read and interprets the header explicity saying that the data is in JSON format, it tries to decode and the result is the same exception that you get when you do that: JSON.parse("field1=value1&k=j").
To solve this, you need to send "post_fields" as an empty hash, and send your actual data by using "post_body". Also, you need to convert your hash to json manually with to_json.
I don't know if they (the curb project owners) know this problem, but I suggest you to warning them about it.

Can't mock website with Basic Authentication

Using Ruby, Mechanize, RSpec, and Webmock, I can not mock a website with Basic Authentication, my app keeps telling me that I got an unregistered stub.
The stubs:
stub_request(:get, "http://foo:bar#google.fr:80/").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})
Net::HTTP.start('www.google.fr') {|http|
req = Net::HTTP::Get.new('/')
req.basic_auth 'foo', 'bar'
http.request(req)
}
In the app:
url = 'http://www.google.fr'
agent = Mechanize.new
agent.add_auth(url, 'foo', 'bar')
agent.get(url)
The issue I get when running agent.get(url)
(rdb:1) agent.get(url)
*** WebMock::NetConnectNotAllowedError Exception: Real HTTP connections are disabled. Unregistered request: GET http://www.google.fr/ with headers {'Accept'=>'*/*', 'Accept-Charset'=>'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Accept-Encoding'=>'gzip,deflate,identity', 'Accept-Language'=>'en-us,en;q=0.5', 'Connection'=>'keep-alive', 'Host'=>'www.google.fr', 'Keep-Alive'=>'300', 'User-Agent'=>'Mechanize/2.7.3 Ruby/1.9.3p194 (http://github.com/sparklemotion/mechanize/)'}
You can stub this request with the following snippet:
stub_request(:get, "http://www.google.fr/").
with(:headers => {'Accept'=>'*/*', 'Accept-Charset'=>'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Accept-Encoding'=>'gzip,deflate,identity', 'Accept-Language'=>'en-us,en;q=0.5', 'Connection'=>'keep-alive', 'Host'=>'www.google.fr', 'Keep-Alive'=>'300', 'User-Agent'=>'Mechanize/2.7.3 Ruby/1.9.3p194 (http://github.com/sparklemotion/mechanize/)'}).
to_return(:status => 200, :body => "", :headers => {})
registered request stubs:
stub_request(:get, "http://foo:bar#www.google.fr/").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'})
A few points:
Assigning 'http://foo:bar#google.fr/' to url does
not work neither (and that would be very ugly if it works anyways).
Last but not least, creating a stub with http://www.google.fr/' as a url would not use basic authentication, since if I do so, even if I change the credentials, I will still access to my mocked page and no errors would be rendered.
Some screenshots:
There exists an incompatibility between WebMock and net-http-persistent.
See https://github.com/bblimke/webmock#connecting-on-nethttpstart
Add WebMock.allow_net_connect!(:net_http_connect_on_start => true) to your test set up.
According to the documentation this should work:
stub_request(:get, "foo:bar#www.google.fr").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "", :headers => {})

Webmock not registering my request stubs correctly

I am registering a request stub as follows:
url = "http://www.example.com/1"
stub_request(:get, url).
with(body: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n <id>1</id>\n</project>\n",
headers: {
'Accept' => 'application/xml',
'Content-type' => 'application/xml',
'User-Agent' => 'Ruby',
'X-Trackertoken' => '12345'
}).
to_return(status: 200, body: '', headers: {})
for some reason when I run bundle exec rspec spec, my specs fails saying that the request isn't registered yet. The registered stub is this,
stub_request(:get, "http://www.example.com/1").
with(body: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n <id>1</id>\n</project>\n",
headers: {
'Accept' => 'application/xml',
'Content-type' => 'application/xml',
'User-Agent' => 'Ruby',
'X-Trackertoken' => '12345'
})
note that the to_return part is missing
I tried replacing the body header with an empty string, the request stub is registered correctly but then my specs will still fail because they are expecting some value from the body other than the empty string. Thus, it is really important that I assign a value to body.
In my spec I am calling this method:
def find(id)
require 'net/http'
http = Net::HTTP.new('www.example.com')
headers = {
"X-TrackerToken" => "12345",
"Accept" => "application/xml",
"Content-type" => "application/xml",
"User-Agent" => "Ruby"
}
parse(http.request(Net::HTTP::Get.new("/#{id}", headers)).body)
end
Any ideas on why this is happening?
Thanks.
The problem is that your stub is matching a GET request with a non-empty body of <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n <id>1</id>\n</project>\n, but when you make the request you're not including any body, so it doesn't find the stub.
I think you're confused about what body is what here. The body in the with method arguments is the body of the request you are making, not the body of the response. What you probably want is a stub like this:
url = "http://www.example.com/1"
stub_request(:get, url).
with(headers: {
'Accept' => 'application/xml',
'Content-type' => 'application/xml',
'User-Agent' => 'Ruby',
'X-Trackertoken' => '12345'
}).
to_return(status: 200,
body: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project>\n <id>1</id>\n</project>\n",
headers: {})

Ruby Multi-part Form Upload with RestClient

I'm working on a ruby application, and am trying to upload a file to box.net. I have it working with the curl call
curl https://www.box.com/api/2.0/files/data -H "Authorization: BoxAuth api_key=<API_KEY>&auth_token=<AUTH_TOKEN>" -F folder_id=0 -F filename=#test.txt --trace ~/Desktop/log.txt
I've tried to translate this into ruby, and have tried the following
request = RestClient::Request.new(:method => :post,:url => "https://www.box.com/api/2.0/files/data",:authorization => "BoxAuth api_key=<API_KEY>&auth_token=<AUTH_TOKEN>",:filename => "test.txt", :payload => { :multipart => true, :file => File.new("test.txt"))
request.execute
but I keep getting back a "401: Unauthorized" response. I've also tried using the box-api gem, but that seems to only work with version 1.0 of the API, and I'm trying to interface with 2.0.
Try to use :headers => {:authorization => "BoxAuth api_key=<API_KEY>&auth_token=<AUTH_TOKEN>"} in the call. That should fix the missing authorization header.
Complete request would then be:
request = RestClient::Request.new(:method => :post,:url => "https://www.box.com/api/2.0/files/data",:headers => {:authorization => "BoxAuth api_key=<API_KEY>&auth_token=<AUTH_TOKEN>"},:filename => "test.txt", :payload => { :multipart => true, :file => File.new("test.txt")})

Can I use rest-client to POST a binary file to HTTP without multipart?

I have tried to do the following, but the web-service is NOT REST and does not take multi-part. What do I do in order to POST the image?
#response = RestClient.post('http://www.postful.com/service/upload',
{:upload => {
:file => File.new("#{#postalcard.postalimage.path}",'rb')
}
},
{"Content-Type" => #postalcard.postalimage.content_type,
"Content-Length" => #postalcard.postalimage.size,
"Authorization" => 'Basic xxxxxx'
} # end headers
) #close arguments to Restclient.post
Got the answer: use I/O to stream as a string instead of using File.new....
:file => IO.read("#{#postalcard.postalimage.path}")

Resources