Ruby on Rails 2.1 - 檔案上傳



您可能需要一個讓網站訪問者將檔案上傳到伺服器的功能。Rails 使得處理此需求非常容易。現在,我們將繼續進行一個簡單的小型 Rails 專案。

像往常一樣,讓我們從一個名為 **upload** 的新 Rails 應用程式開始。讓我們使用簡單的 rails 命令建立一個應用程式的基本結構。

C:\ruby> rails -d mysql upload

讓我們決定您希望將上傳的檔案儲存到哪裡。假設這是公共部分內的 **data** 目錄。因此,請建立此目錄並檢查許可權。

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

我們的下一步將是像往常一樣,建立控制器和模型。

建立模型

由於這不是一個基於資料庫的應用程式,我們可以保留任何我們覺得方便的名稱。假設我們必須建立一個 **DataFile** 模型。

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 物件 **upload**,並使用輔助函式 **original_filename** 提取上傳的檔名,最後將上傳的檔案儲存到“public/data”目錄中。您可以呼叫輔助函式 **content_type** 來了解上傳檔案的媒體型別。

這裡 **File** 是一個 Ruby 物件,**join** 是一個輔助函式,它將連線目錄名和檔名,並返回完整的檔案路徑。

接下來,要以寫入模式開啟檔案,我們使用 **File** 物件提供的 open 輔助函式。此外,我們正在讀取傳遞的資料檔案中的資料並寫入輸出檔案。

建立控制器

現在,讓我們為我們的上傳專案建立一個控制器:

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

在這裡,我們呼叫了在模型檔案中定義的函式。**render** 函式用於重定向到檢視檔案以及顯示訊息。

建立檢視

最後,我們將建立一個檢視檔案 **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"** 指定為方法名稱,當您單擊 **Upload** 按鈕時將呼叫此方法。

它將向您顯示如下螢幕:

Upload File

現在,您選擇一個檔案並上傳它。此檔案將以實際檔名上傳到 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 參考手冊**。

廣告
© . All rights reserved.