DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Home-brewed File Upload In Ruby On Rails

03.29.2006
| 56723 views |
  • submit to reddit
        Most of this comes from others' work, but I was able to tool it to my needs and fix some bugs.  All of these lines go in the model, which for me has a :file and :content_type attributes.  :file stores the complete path to the uploaded file.  Be sure to change the string in path_to_file to the place where you want files stored, and that proper permissions are set on that path.  Also, sanitize_filename doesn't HAVE to be a private method -- make it public if you want.

### Model ###
 def file=(uploaded_file)  
    @uploaded_file = uploaded_file
    @filename = sanitize_filename(@uploaded_file.original_filename)
    write_attribute("content_type", @uploaded_file.content_type)
  end
  
  def after_create
    if !File.exists?(File.dirname(path_to_file))
      Dir.mkdir(File.dirname(path_to_file))
    end
    if @uploaded_file.instance_of?(Tempfile)
      FileUtils.copy(@uploaded_file.local_path, path_to_file)
    else
      File.open(self.path_to_file, "wb") { |f| f.write(@uploaded_file.read) }
    end
    write_attribute("file", path_to_file)
  end

  def after_destroy
    if File.exists?(self.file)
      File.delete(self.file)
      Dir.rmdir(File.dirname(self.file))
    end
  end
  
  def path_to_file
    File.expand_path("#{RAILS_ROOT}/upload/#{self.id}/#{@filename}")
  end
  
  private
  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.gsub(/[^\w\.\_]/,'_') 
  end
  
### View ###
...
<input type="file" name="model[file]" />
...
    

Comments

karel zeman replied on Thu, 2009/01/15 - 5:33am

You are a god send! I’ve spent a week battling with Java applets and was getting discouraged after seeing all of the (wonderfully attractive) Flash/Cold Fusion uploaders. Who would have known that I could find a Rails/Flash uploader - exactly what I was looking for. Anyway - thanks.

Snippets Manager replied on Thu, 2007/04/26 - 7:07pm

hello, i am developping a web rails application and the difficuty is to upload file in a parametre path and also i must save other information in Upload_FILE table i want to create a function upload_file(file,path) that save file in path can you help me

Snippets Manager replied on Wed, 2006/03/29 - 10:25pm

This code is so old... better to use attachment_fu!

Snippets Manager replied on Mon, 2006/09/04 - 11:34pm

I am using this code in 1.1.2, had to make a few changes: class SingleFile < ActiveRecord::Base def file=(uploaded_file) @uploaded_file = uploaded_file @filename = sanitize_filename(@uploaded_file.original_filename) write_attribute(:content_type, @uploaded_file.content_type) end def after_create if !File.exists?(File.dirname(self.path)) FileUtils.mkdir_p(File.dirname(self.path)) end if @uploaded_file.instance_of?(Tempfile) FileUtils.copy(@uploaded_file.local_path, self.path) else File.open(self.path, "wb") { |f| f.write(@uploaded_file.read) } end write_attribute(:file, self.simple_path) self.save end def after_destroy if File.exists?(self.file) File.delete(self.file) Dir.rmdir(File.dirname(self.file)) end end def simple_path "#{self.id}/#{@filename}" end def path File.expand_path("#{RAILS_ROOT}/public/files/#{self.id}/#{@filename}") end private 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.gsub(/[^\w\.\_]/,'_') end end

Snippets Manager replied on Sun, 2006/04/16 - 5:07am

I am a newb to both Ruby and Rails, but I personally was unable to get Dir.mkdir to work in the example. FileUtils.mkdir_p() seemed far more effective, as it can create complete paths (directory and any necessary parent directories): Options: mode noop verbose Creates a directory and all its parent directories. For example, FileUtils.mkdir_p '/usr/local/lib/ruby' causes to make following directories, if it does not exist. * /usr * /usr/local * /usr/local/lib * /usr/local/lib/ruby You can pass several directories at a time in a list. So basically I replaced the two appearances of Dir.mkdir() with FileUtils.mkdir_p() and it worked perfectly.

Snippets Manager replied on Thu, 2006/03/30 - 8:44am

I tried your code last night and couldn't get it to work, I found that the write_attribute was not working correctly on the database. commented those two lines out in file=(uploaded_file) method and also in the def after_create methods. I put the new lines in the def file=(uploaded_file) method, and here they are... self.content_type = @uploaded_file.content_type self.file = path_to_file