Tutorials Point


  Learning Ruby on Rails 2.1
  Advanced Ruby on Rails 2.1
  Ruby on Rails Quick Guide
  Ruby Tutorial
  Ruby on Rails Resources
  Selected Reading

Copyright © 2014 by tutorialspoint



  Home     References     Discussion Forums     About TP  

File Uploading using Rails 2.1


previous next AddThis Social Bookmark Button

Advertisements

You may have a requirement in which you want your site visitors to upload a file on your server. Rails makes it very easy to handle this requirement. Now we will proceed with a simple and small Rails project.

As usual, let's start off with a new Rails application called upload. So let's create basic structure of the application by using simple rails command.

C:\ruby> rails -d mysql upload

Here we are using -d mysql option to specify our interest to use MySQL database. We can specify any other database name like oracle or postgress using -d option. By default Rails uses SQLite database.

Setting up the Database:

Even though we are not using a database in our application but Rails needs it to proceed. So let's perform these additional steps.

Here is the way to create database:

mysql> create database upload;
Query OK, 1 row affected (0.01 sec)

mysql> grant all privileges on upload.*
 to 'root'@'localhost' identified by 'password';
Query OK, 0 rows affected (0.00 sec)

mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)

To tell Rails how to find the database, edit the configuration file ~\upload\config\database.yml and change the database name to cookbook. When you finish, it should look something like:

development:
  adapter: mysql
  encoding: utf8
  database: upload
  username: root
  password: password
  host: localhost
test:
  adapter: mysql
  encoding: utf8
  database: upload
  username: root
  password: password
  host: localhost
production:
  adapter: mysql
  encoding: utf8
  database: upload
  username: root
  password: password
  host: localhost

Now let's decide where you would like to save your uploaded files. Assume this is data directory inside your public section. So create this directory and check the permissions.

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

Our next step will be as usual, to create controller and models, so let's do that:

Creating Model:

Because this is not a database based application so we can keep name whatever is comfortable to us. Assume we have to create a DataFile model.

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

Now we will create a method called save in upload/app/models/data_file.rb model file. This method will be called by the application controller.

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

The above function will take CGI object upload and will extract uploaded file name using helper function original_filename and finally it will store uploaded file into "upload/public/data" directory. You can call helper function content_type to know media type of the uploaded file.

Here File is a ruby object and join is a helper function will concatenate directory name alongwith file name and will return full file path.

Next, to open a file in write mode we are using open helper function provided by File object. Further we are reading data from the passed data file and writing into output file.

Creating Controller:

Now let's create a controller for our upload project:

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

Now we will create two controller functions first function index will call a view file to take user input and second function uploadFile takes file information from the user and passes it to the 'DataFile' model. We set the upload directory to the 'uploads' directory we created earlier "directory = 'data'".

So open your upload/app/controllers/upload_controller.rb file and save the following code:

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

Here we are calling a function save which is defined in model file. The render function is being used to redirect to view file as well as to display a message.

Creating View:

Finally we will create a view file app/views/upload/uploadfile.html.erb which we have mentioned in our controller file. Populate this file with the following code:

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

Here everything is same what we have explained in earlier chapters. Only new tag is file_field which will create a button to select a file from user's computer.

By setting the multipart parameter to true, you ensure that your action properly passes along the binary data from the file.

Here important point to note is that we have given uploadFile method name in :action, which will be called when your will click Upload button.

Now start your webserver as follows:

C:\ruby\upload> ruby script/server

Try browsing http://localhost:3000/upload/index to get the input screen. This will show you a screen as follows:

Upload File

Now you select a file and upload it, this file will be uploaded into app/public/data directory with the actual file name and a message will be displayed to you saying that "File has been uploaded successfully".

NOTE: If a file with the same name already exists in your output directory then it will be over-written.

Files uploaded from Internet Explorer:

Internet Explorer includes the entire path of a file in the filename sent, so the original_filename routine will return something like:

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

instead of just:

My File.jpg

This is easily handled by File.basename, which strips out everything before the filename.

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

Deleting an existing File:

If you want to delete any existing file then its simple and need to write following method in your controller file:

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

For a complete detail on File object, you need to go through Ruby Reference Manual.



previous next Printer Friendly

Advertisements


  

Advertisements