post image with faraday as parameter - ruby-on-rails

I have a old service and new service with images on it. I want to migrate the images from old to new. for that I need to get image from my old service and then post it to new sinatra service.
I was able to post image in the format i want using NET::HTTP
url = URI.parse('http://0.0.0.0:9292/')
File.open("./Belgium.png") do |jpg|
req = Net::HTTP::Post::Multipart.new url.path, {"image" => UploadIO.new(jpg, "image/jpeg", "Belgium.jpg"), id:4234}
res = Net::HTTP.start(url.host, url.port) do |http|
http.request(req)
end
end
The params that I get with above post method at my sinatra service are
params = {"image"=>
{:filename=>"Belgium.jpg", :type=>"image/jpeg",:name=>"image",:tempfile=> #<File:/var/folders/h7/f9cvygqs3lg78kwh24v8yzp80000gn/T/RackMultipart20120827-76057-1f3inkn>,
:head=> "Content-Disposition: form-data; name=\"image\";filename=\"Belgium.jpg\"\r\nContent-Length: 28228\r\nContent-Type: image/jpeg\r\nContent-Transfer-Encoding: binary\r\n"},
"id"=>"4234"}
But I wasn't able to get the same result with faraday. I tried using something like:
payload = { :profile_pic => Faraday::UploadIO.new('avatar.jpg', 'image/jpeg') }
Faraday.post 'http://0.0.0.0:9292/', payload
At my service I get something like this:
"#<'UploadIO:0x007fb950373de8>" An object. This is not what i expect at my service.
How can I get the same behaviour as I get with Net::HTTP. I think it has go to do something with middleware, I tried tweaking around but I am still a newbie.

What about:
conn = Faraday.new(:url => 'http://0.0.0.0:9292' ) do |faraday|
faraday.request :multipart
end
payload = { :profile_pic => Faraday::UploadIO.new('avatar.jpg', 'image/jpeg') }
conn.post 'http://0.0.0.0:9292/', payload

Related

The content type 'application/x-www-form-urlencoded' is not supported in Ruby on Rails

So I'm just trying to make a simple post request using httpclient in RoR.
I'm going through a proxy, doing ntlm authentication with the server ( I can make GET requests without a problem).
Now when I try and do a post request, I get the error mentioned in the title...
proxy = ENV['HTTP_PROXY']
client=HTTPClient.new(proxy)
client.set_auth(nil,user,pass)
body= [{'Content-Type' => 'application/atom+xml, :content => ...}]
res = client.post('url',body)
puts res.body
How am i getting this error when I clearly specify the header as atom+xml..?
You should use
res = client.post('url',
:body => "...body content...",
:header => {'Content-Type' => 'application/atom+xml'})

Rails email using Postmark API on Heroku -- connection reset by peer

I have multiple bruises today, trying to learn two things at once... the API for Postmark and Rails HTTP requests.
Goal: Use Postmark add-on for Heroku to send production email.
I am trying to combine this article on HTTP requests...
http://docs.ruby-lang.org/en/2.0.0/Net/HTTP.html
... with this API reference for Postmark...
http://developer.postmarkapp.com/developer-send-api.html
Unfortunately, the examples from Postmark are done in curl and I have not succeeded in translating them into a HTTP request. I suspect the problem centers around the headers -- the parts of the transmission other than the body.
The rescue clause seen in the code below traps the error 'connection reset by peer'. At this point I don't know if I am even close to the right format for the headers that provide Postmark authentication.
I have the proper server token (in the config entry) and the From email has been given the required Postmark signature.
def send_production_email(email_address, subject, email_body)
# Use API to interact with Heroku add-on Postmark
# http://developer.postmarkapp.com/developer-send-api.html
uri = URI('https://api.postmarkapp.com/email')
# Form the request
req = Net::HTTP::Post.new(uri)
# Set request headers -- SUSPECT THIS IS WRONG
req['Accept'] = 'application/json'
req['Content-Type'] = 'application/json'
req['X-Postmark-Server-Token'] = Rails.application.config.postmark_token
rbody ={
'From' => 'Support <michael#mydomain.com>',
'To' => email_address,
'Subject' => subject,
'HtmlBody' => wrap_html(email_body),
'TextBody' => email_body
}.to_json
req.body = rbody
# Send the request, waiting for the response
begin
response = Net::HTTP.new(uri.host, uri.port).start {|http| http.request(req) }
rescue Exception => e
logthis("http request error: #{e.message}")
return
end
# ...parsing section omitted since I do not get that far...
end
A second attempt was formatted this way, but results in the same peer reset error:
rbody ={
'From' => 'Support <michael#disambiguator.com>', # TODO: replace email when domain is live
'To' => email_address,
'Subject' => subject,
'HtmlBody' => wrap_html(email_body),
'TextBody' => email_body
}.to_json
uri = URI('https://api.postmarkapp.com/email')
http = Net::HTTP.new(uri.host, uri.port)
# http.use_ssl = true
request = Net::HTTP::Post.new(uri.path, {'Content-Type' => 'application/json', 'Accept' => 'application/json', 'X-Postmark-Server-Token' => Rails.application.config.postmark_token})
request.body = rbody
# Send the request, waiting for the response
begin
response = http.request(request)
rescue Exception => e
logthis("http request error: #{e.message}")
return
end
I am grateful for any guidance!
I’m a Wildbit’s employee and the maintainer of the official Postmark Ruby gem.
The "connection reset by peer" error is the result of you trying to send an unencrypted HTTP request to an endpoint expecting secure communication via HTTPS. So, if you change this line:
Net::HTTP.new(uri.host, uri.port).start {|http| http.request(req) }
to:
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
response = http.start { |http| http.request(req) }
then you should be able to receive a response from the API. I see that you have this line in the second example, but it is commented. Since you’re doing this as an exercise, I’d like to add that when using net/http you don’t usually have to work with the underlying classes like Net::HTTP::Post. It’s generally simpler to use the higher level API provided by instances of the Net::HTTP class. Here is an example of how your method could be simplified by using it:
def send_production_email(email_address, subject, email_body)
uri = URI('https://api.postmarkapp.com/email')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
headers = {'Accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Postmark-Server-Token' => Rails.application.config.postmark_token}
payload = {'From' => 'tema#wildbit.com',
'To' => email_address,
'Subject' => subject,
'HtmlBody' => email_body,
'TextBody' => email_body}
http.post(uri.request_uri, payload.to_json, headers)
rescue => e
puts "http request error: #{e.message}"
end
And, if you’re interested in how net/http is used in the official Postmark Ruby gem, check out the HttpClient class’ source.

Rails - Sending image using Faraday

I'm trying to make a request to an API sending an image and some other data, and getting the response. That's my code:
file = "assets/images/test.jpg"
conn = Faraday.new(:url => "api_url" ) do |faraday|
faraday.request :multipart
end
payload = { :profile_pic => Faraday::UploadIO.new(file, 'image/jpeg') }
conn.post "/test", payload
My first problem is that I'm always getting the following error:
Errno::ENOENT (No such file or directory - assets/images/test.png)
I've tried all the paths I could imagine. Where should be saved the image in directories to be found by Faraday?
The second question is about the response, how can I get the response and handle it?
The third one is that, I haven't understand what's the utility of the first parameter of the last call:
conn.post "/hello", payload
I've written "/hello" but don't have any idea about what's the real usage.
And the last one. Could I send a raw image saved in a variable instead of sending a path to Faraday?
EDIT
Now it's working, this is the solution:
Be aware that url must be only until .com, the rest of the path must go on conn.post like this example /v1/search.
c.adapter :net_http was needed too.
Message response is correctly handled in json variable.
Solution:
url = 'http://url.com'
file = Rails.root.to_s + "/app/assets/images/test.jpg"
conn = Faraday.new(:url => url ) do |c|
c.request :multipart
c.adapter :net_http
end
payload = { :image => Faraday::UploadIO.new(file, 'image/jpeg'), :token => token}
response = conn.post '/v1/search', payload
json = JSON.parse response.body
You should try this for your first question :
file = Rails.root.to_s + "/app/assets/images/test.jpg"
For your third question, the first parameters allows you to construct the right URL from the base "api_url". Please see the example from the Readme.
## POST ##
conn.post '/nigiri', { :name => 'Maguro' } # POST "name=maguro" to http://sushi.com/nigiri

Why Rails (current 4.0) fails to interpret nested JSON (from a HTTP POST)?

I am writing a simple client server application (using only JSON API) with Ruby (client) and Rails (server).
When trying to create a game from client, I am using:
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"tttgame" => {"name" => "Marius"}})
resp = http.request(request)
On server side (tttgames_controller.rb) I have:
# POST /tttgames
# POST /tttgames.json
def create
#tttgame = Tttgame.new(tttgame_params)
...
end
...
def tttgame_params
params.require(:tttgame).permit(:name)
end
Logs on server are:
Started POST "/tttgames.json" for 127.0.0.1 at 2013-10-05 12:58:44 +0300
Processing by TttgamesController#create as JSON
Parameters: {"tttgame"=>"{\"name\"=>\"Marius\"}"}
Completed 500 Internal Server Error in 0ms
NoMethodError (undefined method `stringify_keys' for "{\"name\"=>\"Marius\"}":String):
app/controllers/tttgames_controller.rb:33:in `create'
How can I fix this? All examples from the Internet are looking the same. Thanks!
Both methods set_form_data and post_form are encoding data using format x-www-form-urlencoded. Check here.
Examples that are provided do not contain nested hashes.
I have found here an example, under the REST methods section, which works very well.
Thus, in order to get on server a valid structure with nested hashes, the client should use square brackets:
uri = URI.parse(url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data({"tttgame[name]" => “Marius”)
resp = http.request(request)
or much simpler:
uri = URI.parse(url)
resp = Net::HTTP.post_form(uri, {"tttgame[name]" => “Marius”})
This will generate on server
Parameters: {"tttgame"=>{"name"=>"Marius"}}
You might want to do this instead. It's even more compact.
uri = URI.parse(url)
resp = Net::HTTP.post_form(uri, "tttgame" => {"name" => "Marius"})
From http://ruby-doc.org/stdlib-2.0.0/libdoc/net/http/rdoc/Net/HTTP.html#label-POST+with+Multiple+Values
UPDATE: In addition, your String is not a valid JSON. It needs to be "{\"name\":\"Marius\"}" instead.
You need to parse that response, because right now it is a String ("{\"name\"=>\"Marius\"}") but you actually need a Hash ({"name" => "Marius"}).
Therefore #stringify_keys fails because it is a method that operates on a Hash.
So do a:
#tttgame = Tttgame.new(JSON.parse(tttgame_params))
instead. This will turn your serialized JSON response into a Hash from a String.

POST over HTTPS Ruby on Rails

I need to call an external url to pull down some information from a remote database.
I tried setting up my call like this:
post_params = {'a' => 'b', 'b' => 'c',}
resp = Net::HTTP.post_form(URI.parse('https:/my.remoteserver.com/'), post_params)
This returns with a 400 Bad Request, however, due to the fact that the url is HTTPS.
If I format the call as a GET, however, and do something like this:
url = URI.parse("https:/my.remoteserver.com?a=b&b=c")
result = Net::HTTP.start(url.host, use_ssl: true, verify_mode: OpenSSL::SSL::VERIFY_NONE) do
|http| http.get url.request_uri, 'User-Agent' => 'MyLib v1.2'
end
Everything works fine. Unfortunately in my specific case I can't use GET. I assume there is a way to do this over POST but I just don't know what that would be. If anyone could help me out with this I'd really appreciate it. Thanks!
The key part of the other answer's link, and cause of your problem could be because you need to set use_ssl = true on the Net::HTTP element:
Example:
post_params = {'a' => 'b', 'b' => 'c',}
uri = URI 'https:/my.remoteserver.com/'
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true if uri.scheme == 'https'
resp = http.post_form(uri, post_params)

Resources