views:

59

answers:

2

Hello!

I am new to ruby and to rails, so excuse my question... . What i want to know is, how to take a file from a ftp server with ruby without saving the file on my rails application harddrive (streaming the filedata direct to the client). I am working with the ruby Net/FTP class.

With the method "retrbinary" from the Net/FTP class i have the following snippet:

ftp.retrbinary('RETR ' + filename, 4096) { |data|
  buf << data
}

In my rails view i can do something like this:

send_data( buf )

So how do i combine these two. I dont know how to instanziate a buffer object, fill in the stream and than serve it to the user. Has anybody an idea how to do this?

A: 

Do you want the following?

1) Client (browser) sends a request to the Rails server

2) Server should respond with the contents of a file that is located on an ftp server.

Is that it?

If so, then simply redirect the browser to the ftp location. Eg

 # in controller
 ftp_url = "ftp://someserver.com/dir_name/file_name.txt
 redirect_to ftp_url

The above works if the ftp file has anonymous get access.

If you really need to access the file from the server and stream it, try the following:

# in controller
render :text => proc {|response, output|
  ftp_session = FTP.open(host, user, passwd, acct)
  ftp_session.gettextfile(remotefile) {|data| output.write(data)}
  ftp_session.close
  }

You should check the headers in the response to see if they're what you want.

ps. Setting up the ftp connection and streaming from a second server will probably be relatively slow. I'd use JS to show a busy graphic to the user.

I'd try alternatives to ftp. Can you set up an NFS connection or mount the remote disk? Would be much faster than ftp. Also investigate large TCP window sizes.

Larry K
A: 

Hello Larry,

thank you very much for your support! Your post get me going on. After some cups of coffee i found a working solution. Actually i am doing the following, which works for me:

def download_file
  filename = params[:file]
  raw = StringIO.new('')
  @ftp.retrbinary('RETR ' + filename, 4096) { |data|
    raw << data
  }
  @ftp.close
  raw.rewind
  send_data raw.read, :filename => filename
end

I will test this in production(real life situation). If this is not working well enough, i have to use a NFS mount.

fin

fin