Never been to DZone Snippets before?

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

Home-brewed file upload in Ruby on Rails (See related posts)

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 on this post

Psikotic posts on Mar 30, 2006 at 19:37
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
Eleo posts on Apr 16, 2006 at 05:11
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.
winton posts on Sep 04, 2006 at 23:41
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
seancribbs posts on Apr 25, 2007 at 11:12
This code is so old... better to use attachment_fu!
massinissa posts on Apr 26, 2007 at 19:17
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

You need to create an account or log in to post comments to this site.


Click here to browse all 4860 code snippets

Related Posts