So this particular programming conundrum I find myself in is quite a bit above my Ruby skills or any programming skills in general I guess.
Using an HTML (Post) form I am able to upload an image to my server side CGI script and from there I am able to take the data and then save it on my server. The bones of HTML required to do this, with all of the formatting fluff stripped away is essentially:
I really donāt understand how this works, other than the HTML form is able to select the file from the client end and then transfer it to my CGI/Perl file (logoupload.pl). On the server end I have some code in place that checks for errors, size etcā¦ and then saves the file to the directory of my choosing.
This is all good, I can make this work.
Now what I want to try and do is within Ruby (given a path to an existing image file) send that image file to my same server side CGI script using some type of GET or POST call.
I have no idea how to do this.
My typical way I make calls to my server (or any other website address) is something like this:
some_url = "http://design.medeek.com/resources/somescript.pl?var1=#{@Var1}&var2=#{Var2}&var3=#{@Var3}"
require 'open-uri'
begin
open(some_url) { |io|
url_response = io.read
# Then parse the response with some code here or convert JSON to ruby array etc...
}
rescue StandardError => e
UI.messagebox ("Unable to connect to server, action aborted.")
end
How would I send an image via a URL call like this? Or is there a better way to do this?
I really have no idea what all those carriage returns and new lines are doing in the code, Iām just trying to follow the documentation but I think there is something messed up in the way I have these special characters inserted and that is what is making this not work.
Maybe someone can spot what I have wrong with the building of the post_body.
If I use the above HTML form with a couple of parameters/inputs added, it works flawlessly and the image file is uploaded to the server and processed by my CGI and saved in the appropriate folder. Ruby on the other hand is somehow munging it up, but Iām not sure how yet.
For those who need to or would like to send files via SketchUp here is what Iāve got and it seems to finally work:
# Send HTTP request to Medeek Server with Image Upload
require "net/http"
require "uri"
uri = URI.parse("http://design.medeek.com/imageupload.pl")
req = Net::HTTP::Post.new(uri)
req.set_form([['shn', '19AD55XC21WO78PQ21'], ['timestamp', new_timestamp], ['action', 'copylogo'], ['action2', File.open(imagefilename), {filename: "#{File.basename(imagefilename)}"}]], 'multipart/form-data')
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
medeek_response = http.request(req)
if medeek_response.body =~ /Success/i
# Do nothing upload successful
else
UI.messagebox ("Upload of logo to the Medeek Server failed, please try again.")
puts "#{medeek_response.code}"
end
puts "#{medeek_response.body}"
end
Well I guess this one wasnāt above my programming pay grade but it did take about 8 hours of mucking about and some serious hair pulling until I finally found a solution that worked.
use the following, which opens the file read-only and binary, which would be normal for an image file.
File.open(imagefilename, 'rb')
Revised code
require "net/http"
require "uri"
imagefilename = '/mnt/c/r_su/medeek.rb'
new_timestamp = 'TIMESTAMP'
file = File.open imagefilename, 'rb'
fields = [
['shn', '19AD55XC21WO78PQ21'],
['timestamp', new_timestamp],
['action', 'copylogo'],
['action2', file, {filename: "#{File.basename(imagefilename)}"}]
]
uri = URI.parse("http://[::1]:40001")
req = Net::HTTP::Post.new(uri)
req.set_form(fields, 'multipart/form-data')
res = Net::HTTP.start(uri.hostname, uri.port) do |http|
medeek_response = http.request(req)
if medeek_response.body =~ /Success/i
# Do nothing upload successful
else
STDOUT.puts "Upload of logo to the Medeek Server failed, please try again."
STDOUT.puts "#{medeek_response.code}"
end
puts "#{medeek_response.body}"
end
file.close unless file.closed?
As to all the strange āpost_bodyā code from the example, thatās how āmultipart/form-dataā encodes the data āpairsā in the body of the POST request. Using net/http is much easierā¦
As to closing the file handle, thatās very important, especially on Windows. Windows is much different that macOS (and Ubuntu, etc), as it does not allow file operations if the file has an open handleā¦
Okay, I get what your doing, your wrapping the whole thing with the file open method, which automatically closes out the file, thank-you for the clarification.
First of all, sorry for not noticing the STDOUT. I ran the code in stand-alone Ruby, as I was also running a server that allowed me to look at the body the Net::HTTP request was sending.
Using STDOUT is kind of an autopilot thing with me, as sometimes I use STDOUT.syswrite, which canāt be used without an IO instance with it.
So, donāt use STDOUT with SU, just use puts. Also, what Dan suggested (using File.open with a block) would work fine.
I didnāt add it to the code I listed, but if you use File.open without a block, I would put the file.close unless file.closed? statement in a begin/ensure block to make sure it runs even if an error is raised.
Would it be okay to put the open and close for the file before this entire section of code?
The close call (or the end of the File.open block) must be after all the Net::HTTP code finishes. The Net::HTTP code pulls from the opened object (file) as it streams the data to the web server. Your file may be small, but this can be used with large files (~100Mb or larger)ā¦
See Class: File ā Core Ruby-2.7.8 pp225. If you see the āTable of Contentsā pane (you may need to be full screen with the browser window), type ācloseā in its search box, and youāll see IO.close listed, it should also be in the main doc window if nothing is āfolded/collapsedā. āRDocā docs, which is what youāre viewing at docs.ruby-lang.org, doesnāt show āancestorā methods very well. Most āYARDā derivatives do show themā¦
I suppose I mostly solved this one on my own but I really appreciate you guys schooling me on my Ruby code, Iām still very much a newbie when it comes to actually coding. Thank-you.