Ruby on Rails 2.1 - 文件上传


您可能有一个要求,希望网站访问者在您的服务器上上传文件。Rails 可以非常轻松地满足这一要求。现在,我们将继续一个简单的小型 Rails 项目。

像往常一样,让我们​​从一个名为upload的新 Rails 应用程序开始。让我们使用简单的 Rails 命令创建应用程序的基本结构。

C:\ruby> rails -d mysql upload

让我们决定您要保存上传的文件的位置。假设这是您的公共部分中的数据目录。因此,创建该目录并检查权限。

C:\ruby> cd upload
C:\ruby\upload> mkdir upload\public\data

我们的下一步将像往常一样,创建控制器和模型。

创建模型

由于这不是基于数据库的应用程序,因此我们可以保留任何适合我们的名称。假设我们必须创建一个数据文件模型。

C:\ruby\upload> ruby script/generate model DataFile
   exists  app/models/
   exists  test/unit/
   exists  test/fixtures/
   create  app/models/data_file.rb
   create  test/unit/data_file_test.rb
   create  test/fixtures/data_files.yml
   create  db/migrate
   create  db/migrate/001_create_data_files.rb   

现在,我们将在data_file.rb模型文件中创建一个名为save的方法。该方法将由应用程序控制器调用。

class DataFile < ActiveRecord::Base
   def self.save(upload)
      name = upload['datafile'].original_filename
      directory = "public/data"
      # create the file path
      path = File.join(directory, name)
      # write the file
      File.open(path, "wb") { |f| f.write(upload['datafile'].read) }
   end
end

上面的函数将上传CGI 对象,并使用辅助函数original_filename提取上传的文件名,最后将上传的文件存储到“public/data”目录中。您可以调用辅助函数content_type来了解上传文件的媒体类型。

这里File是一个 ruby​​ 对象,join是一个辅助函数,它将连接目录名和文件名,并返回完整的文件路径。

接下来,要以写入模式打开文件,我们使用File对象提供的打开辅助函数。此外,我们从传递的数据文件中读取数据并写入输出文件。

创建控制器

现在,让我们为我们的上传项目创建一个控制器 -

C:\ruby\upload> ruby script/generate controller Upload
   exists  app/controllers/
   exists  app/helpers/
   create  app/views/upload
   exists  test/functional/
   create  app/controllers/upload_controller.rb
   create  test/functional/upload_controller_test.rb
   create  app/helpers/upload_helper.rb

现在,我们将创建两个控制器函数。第一个函数index将调用视图文件来获取用户输入,第二个函数uploadFile从用户获取文件信息并将其传递给“DataFile”模型。我们将上传目录设置为我们之前创建的“uploads”目录“directory = 'data'”。

class UploadController < ApplicationController
   def index
      render :file => 'app\views\upload\uploadfile.html.erb'
   end
   def uploadFile
      post = DataFile.save( params[:upload])
      render :text => "File has been uploaded successfully"
   end
end

在这里,我们调用模型文件中定义的函数。渲染函数用于重定向到查看文件以及显示消息

创建视图

最后,我们将创建一个视图文件uploadfile.rhtml,我们在控制器中已经提到过。使用以下代码填充此文件 -

<h1>File Upload</h1>

<% form_tag ({:action => 'uploadFile'},
   :multipart => true) do %>

<p><label for="upload_file">Select File</label> : 

<%= file_field 'upload', 'datafile' %></p>

<%= submit_tag "Upload" %>

<% end %>

这里的一切都与我们在前面的章节中解释过的相同。唯一的新标签是file_field,它将创建一个按钮来从用户计算机中选择文件。

通过将 multipart 参数设置为 true,您可以确保您的操作正确传递文件中的二进制数据。

这里,需要注意的重要一点是,我们在:action中指定了“uploadFile”作为方法名称,当您单击“上传”按钮时将调用该方法。

它将向您显示如下屏幕 -

上传文件

现在,您选择一个文件并上传。该文件将以实际文件名上传到 app/public/data 目录中,并显示一条消息“文件已成功上传”。

注意- 如果输出目录中已存在同名文件,则它将被覆盖。

从 Internet Explorer 上传的文件

Internet Explorer 在发送的文件名中包含文件的完整路径,因此original_filename例程将返回类似 -

C:\Documents and Files\user_name\Pictures\My File.jpg

而不仅仅是 -

My File.jpg

这可以通过File.basename轻松处理,它会删除文件名之前的所有内容。

def sanitize_filename(file_name)
   # get only the filename, not the whole path (from IE)
   just_filename = File.basename(file_name) 
   # replace all none alphanumeric, underscore or perioids
   # with underscore
   just_filename.sub(/[^\w\.\-]/,'_') 
end

删除现有文件

如果您想删除任何现有文件,这非常简单。您需要做的就是编写以下代码 -

def cleanup
   File.delete("#{RAILS_ROOT}/dirname/#{@filename}") 
   if File.exist?("#{RAILS_ROOT}/dirname/#{@filename}")
end

有关File对象的完整详细信息,您需要阅读我们的Ruby 参考手册