zulqarnain
zulqarnain

Reputation: 1735

How do I upload a file with the remote file destination as part of the URL?

I have the following method for uploading files:

def send_to_ftp(sourcefile,host,port,username,password,log_path)
  begin
    ftp =Net::FTP.new
    ftp.connect(host, port)
    ftp.passive = true
    ftp.login(username, password)
    ftp.chdir(host)
    ftp.putbinaryfile(sourcefile)
    ftp.close
    return true
  rescue Exception => err
    puts err.message
    return false
  end
end

When I enter the URL as hostname.com/path/to/ftpupload, I get an error: "name or service not known". However, if I enter only "hostname.com" as the host it works but it means there's no way of determining where to put the file on the ftp server

Upvotes: 2

Views: 3684

Answers (2)

the Tin Man
the Tin Man

Reputation: 160551

The host parameter for connect can't be "hostname.com/path/to/ftpupload". Per the documentation, it:

Establishes an FTP connection to host...

and a "host" would be "hostname.com", so you need to split that string into the components necessary.

I'd take advantage of Ruby's URI class and pass in a full URL:

ftp://hostname.com/path/to/ftpupload

Letting URI parse that makes it easy to grab sections from it:

require 'uri'
uri = URI.parse('ftp://hostname.com/path/to/ftpupload')
uri.host
# => "hostname.com"
uri.path
# => "path/to/ftpupload"

Here's how I'd write it:

require 'uri'

def send_to_ftp(sourcefile, host, username, password, log_path)
  uri = URI.parse('ftp://' + host)

  ftp = Net::FTP.new
  ftp.connect(uri.host, uri.port)
  ftp.passive = true
  ftp.login(username, password)
  ftp.chdir(uri.path)
  ftp.putbinaryfile(sourcefile)
  ftp.close

  true

rescue Exception => err
  puts err.message
  false
end

With two more changes you can simplify the code even more. Change the method definition to:

def send_to_ftp(sourcefile, host, log_path)

and:

  ftp.login(uri.user, uri.password)

allows you to call the code using a URL with the embedded username and password:

username:[email protected]/path/to/ftpupload

which is a standard way of calling an internet resource with the userid and password contained in it.

At that point you're left with:

require 'uri'

def send_to_ftp(sourcefile, host, log_path)
  uri = URI.parse('ftp://' + host)

  ftp = Net::FTP.new
  ftp.connect(uri.host, uri.port)
  ftp.passive = true
  ftp.login(uri.user, uri.password)
  ftp.chdir(uri.path)
  ftp.putbinaryfile(sourcefile)
  ftp.close

  true

rescue Exception => err
  puts err.message
  false
end

and your method call looks like:

send_to_ftp(
  'path/to/source/file', 
  'username:[email protected]/path/to/ftpupload', 
  log_path
)

Upvotes: 3

cabron
cabron

Reputation: 91

You pass the same argument to FTP#connect and FTP#chdir. They actually need separate parts of the full URL, namely domain name and path. Try the following:

domain, dir = host.split('/', 2)
#...
ftp.connect(domain, port) # domain = 'hostname.com'
#...
ftp.chdir(dir) # dir = 'path/to/ftpupload'

Upvotes: 0

Related Questions