Ruby on Rails 2.1 - Upload de arquivo

Você pode ter um requisito no qual deseja que os visitantes do site carreguem um arquivo em seu servidor. Rails torna muito fácil lidar com esse requisito. Agora, prosseguiremos com um projeto Rails simples e pequeno.

Como de costume, vamos começar com um novo aplicativo Rails chamado upload. Vamos criar uma estrutura básica do aplicativo usando o comando rails simples.

C:\ruby> rails -d mysql upload

Vamos decidir onde você gostaria de salvar seus arquivos carregados. Suponha que sejadatadiretório dentro de sua seção pública. Portanto, crie este diretório e verifique as permissões.

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

Nosso próximo passo será, como de costume, criar controlador e modelos.

Criando o modelo

Como este não é um aplicativo baseado em banco de dados, podemos manter qualquer nome que seja confortável para nós. Suponha que temos que criar umDataFile modelo.

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

Agora, vamos criar um método chamado save dentro data_file.rbarquivo de modelo. Este método será chamado pelo controlador de aplicativo.

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

A função acima irá pegar o objeto CGI upload e irá extrair o nome do arquivo enviado usando a função auxiliar original_filenamee, finalmente, armazenará o arquivo carregado no diretório "public / data". Você pode chamar a função auxiliarcontent_type para saber o tipo de mídia do arquivo carregado.

Aqui File é um objeto rubi e join é uma função auxiliar que concatenará o nome do diretório junto com o nome do arquivo e retornará o caminho completo do arquivo.

Em seguida, para abrir um arquivo no modo de gravação, estamos usando a função open helper fornecida pelo Fileobjeto. Além disso, estamos lendo dados do arquivo de dados transmitidos e gravando no arquivo de saída.

Criando controlador

Agora, vamos criar um controlador para nosso projeto de upload -

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

Agora, vamos criar duas funções de controlador. A primeira funçãoindex irá chamar um arquivo de visualização para obter a entrada do usuário, e a segunda função uploadFilepega as informações do arquivo do usuário e as passa para o modelo 'DataFile'. Definimos o diretório de upload para o diretório 'uploads' que criamos anteriormente "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

Aqui, estamos chamando a função definida no arquivo de modelo. orender função está sendo usada para redirecionar para visualizar o arquivo, bem como para exibir uma mensagem.

Criando vista

Finalmente, vamos criar um arquivo de visão uploadfile.rhtml,que mencionamos no controlador. Preencha este arquivo com o seguinte código -

<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 %>

Aqui tudo é igual ao que explicamos nos capítulos anteriores. A única nova tag éfile_field, que criará um botão para selecionar um arquivo do computador do usuário.

Ao definir o parâmetro multipart como true, você garante que sua ação transmita corretamente os dados binários do arquivo.

Aqui, um ponto importante a observar é que atribuímos "uploadFile" como o nome do método em :action, que será chamado quando você clicar no Upload botão.

Ele irá mostrar a você uma tela como a seguir -

Agora, você seleciona um arquivo e carrega-o. Este arquivo será carregado no diretório app / public / data com o nome do arquivo real e uma mensagem será exibida dizendo que "Arquivo foi carregado com sucesso"

NOTE - Se um arquivo com o mesmo nome já existir em seu diretório de saída, ele será sobrescrito.

Arquivos enviados do Internet Explorer

O Internet Explorer inclui todo o caminho de um arquivo no nome do arquivo enviado, portanto, original_filename rotina retornará algo como -

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

Em vez de apenas -

My File.jpg

Isso é facilmente resolvido por File.basename, que remove tudo antes do nome do arquivo.

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

Excluindo um arquivo existente

Se você deseja excluir qualquer arquivo existente, é muito simples. Tudo o que você precisa fazer é escrever o seguinte código -

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

Para um detalhe completo sobre File objeto, você precisa passar por nosso Ruby Reference Manual.