【问题标题】:Rails upload file to ftp serverRails 上传文件到 ftp 服务器
【发布时间】:2011-02-12 04:43:36
【问题描述】:

我正在使用 Rails 2.3.5 和 Ruby 1.8.6,并试图弄清楚如何让用户通过我的 Rails 应用程序将文件上传到另一台机器上的 FTP 服务器。此外,我的 Rails 应用程序将托管在 Heroku 上,这不利于将文件写入本地文件系统。

index.html.erb

<% form_tag '/ftp/upload', :method => :post, :multipart => true do %>
<label for="file">File to Upload</label> <%= file_field_tag "file" %>
<%= submit_tag 'Upload' %>
<% end %>

ftp_controller.rb

require 'net/ftp'

class FtpController < ApplicationController
  def upload
    file = params[:file]
    ftp = Net::FTP.new('remote-ftp-server')
    ftp.login(user = "***", passwd = "***")
    ftp.putbinaryfile(file.read, File.basename(file.original_filename))
    ftp.quit()
  end

  def index
  end

end

目前我只是想让 Rails 应用程序在我的 Windows 笔记本电脑上运行。使用上面的代码,我得到了这个错误

Errno::ENOENT in FtpController#upload
No such file or directory -.... followed by a dump of the file contents

我正在尝试上传一个 CSV 文件,如果这有什么不同的话。有谁知道怎么回事?

【问题讨论】:

    标签: ruby-on-rails ftp


    【解决方案1】:

    在我看来 ftp.putbinaryfile 只是想要文件的路径和名称作为第一个参数。

    【讨论】:

    【解决方案2】:

    经过大量研究和摸索,我最终阅读了 putbinaryfile 方法的源代码,以找出解决 putbinaryfile 限制的方法。这是工作代码,替换此行

    ftp.putbinaryfile(file.read, File.basename(file.original_filename))
    

    ftp.storbinary("STOR " + file.original_filename, StringIO.new(file.read), Net::FTP::DEFAULT_BLOCKSIZE)
    

    如果您想知道,STOR 是一个原始的 FTP 命令,是的。我很惊讶这种情况并不能更容易地由 Ruby 标准库处理,当然需要做什么并不明显。

    如果您的应用在 Heroku 上,请添加此行

    ftp.passive = true
    

    Heroku 的防火墙设置不允许 FTP 主动模式,还要确保您的 FTP 服务器支持被动模式。

    【讨论】:

    • ftp.putbinaryfile(StringIO.new(file.read), file.original_filename, Net::FTP::DEFAULT_BLOCKSIZE) 工作吗?
    • 不,这不起作用,抛出错误“无法将StringIO转换为String”。
    • 嘿,Rails 3 能更好地处理这个问题吗?