logo
  • Jobs
  • About Me
  • Contact
  • Home
« Debugging XSLT with VS2005
Interesting Trivia »

Uploading files to a database using Rails

Posted October 19th, 2007 by Matt Berther

Not long ago, I needed a way for users to upload files and store them in a database. The platform for the application was Ruby on Rails, and I wanted to share my experience here.

The first thing we want to do is generate the table for the attachments:

superbia:~/Projects/Attachments mattb$ script/generate model Attachment
      exists  app/models/
      exists  test/unit/
      exists  test/fixtures/
      create  app/models/attachment.rb
      create  test/unit/attachment_test.rb
      create  test/fixtures/attachments.yml
      create  db/migrate
      create  db/migrate/001_create_attachments.rb

This line does a number of things for us, including generating the model class, an associated unit test and fixture, as well as a migration class. The next thing we want to do is fill out the migration class so that we can create the database table. In our case, we will need a filename, content_type and attachment column.

class CreateAttachments < ActiveRecord::Migration
	def self.up
		create_table :attachments do |t|
			t.column :filename, :string
			t.column :content_type, :string
			t.column :data, :binary
		end
	end
 
	def self.down
		drop_table :attachments
	end
end

Let’s now run this migration to create the table in our database:

superbia:~/Projects/Attachments mattb$ rake db:migrate
(in /Users/mattb/Projects/Attachments)
== CreateAttachments: migrating ===============================================
-- create_table(:attachments)
   -> 0.0218s
== CreateAttachments: migrated (0.0220s) ======================================

The next thing that we’ll need to do is to create a controller to process the submitted attachment.

superbia:~/Projects/Attachments mattb$ script/generate controller Attachments show create
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/attachments
      exists  test/functional/
      create  app/controllers/attachments_controller.rb
      create  test/functional/attachments_controller_test.rb
      create  app/helpers/attachments_helper.rb
      create  app/views/attachments/show.rhtml
      create  app/views/attachments/create.rhtml
class AttachmentsController < ApplicationController
	def show
		@attachment = Attachment.find(params[:id])
		send_data @attachment.data, :filename => @attachment.filename, :type => @attachment.content_type
	end
 
    def create
		return if params[:attachment].blank?
 
		@attachment = Attachment.new
		@attachment.uploaded_file = params[:attachment]
 
		if @attachment.save
			flash[:notice] = "Thank you for your submission..."
			redirect_to :action => "index"
		else
			flash[:error] = "There was a problem submitting your attachment."
			render :action => "new"
		end
	end
end

The relevant snippet of the view code that utilizes this is in new.rhtml:

<% form_tag 'create', :multipart => true do %>
	<%= file_field_tag 'attachment' %>
	<%= submit_tag "Send Attachment" %>
<% end %>

The important parts of the view are the multipart declaration; without this, your file will not be submitted. Also, we take advantage of the file_field_tag helper method to output the file browser.

If we run the application now and try to upload a file, we will be presented with an error, because the uploaded_file method does not exist on the Attachment model. Let’s complete our model.

class Attachment < ActiveRecord::Base
	def uploaded_file=(incoming_file)
		self.filename = incoming_file.original_filename
		self.content_type = incoming_file.content_type
		self.data = incoming_file.read
	end
 
	def filename=(new_filename)
		write_attribute("filename", sanitize_filename(new_filename))
	end
 
	private
	def sanitize_filename(filename)
		#get only the filename, not the whole path (from IE)
		just_filename = File.basename(filename)
		#replace all non-alphanumeric, underscore or periods with underscores
		just_filename.gsub(/[^\w\.\-]/, '_')
	end
end

The meat of this model is the uploaded_file method, which the controller calls, passing the uploaded file. This method is responsible for mapping the incoming file to the attributes expected by our database schema. Additionally, we’re sanitizing the filename, so that we are not only getting just the filename, but we’re also cleaning up any extra characters and replacing them with underscores.

I’ll leave it as an exercise for the reader to associate the attachment with a given user. The “magic” of Rails makes this really straightforward.

5 Comments

This entry was posted on Friday, October 19th, 2007 at 2:05 pm and is filed under Uncategorized. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

links for 2008-05-17 « Bloggitation
May 16th, 2008

[...] Uploading files to a database using Rails (tags: ruby rails multimedia programming) [...]

Greg
July 16th, 2008

What if I want to upload multiple files, for example, select ten files at once and then upload them?

Ace Suares
September 22nd, 2008

Super !
So simple and it stores in the datgabase instead of on disk, where autohorization becomes a problem. Excellent !

Paulo
March 18th, 2009

What if I want to create a link for download of this file saved on the database? please help!

Prasanthi
March 28th, 2009

Given full idea about the specific topic. Provide same clarification to print a page of a rails by giving access to local printers.

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
-->

flag
Favorite Charity
wounded warrior project
Search
Social
  • mattberther on twitter
  • mattberther on linkedin
Syndication
Archives
  • January 2010
  • September 2009
  • July 2009
  • June 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • September 2008
  • August 2008
  • June 2008
  • May 2008
  • April 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • November 2007
  • October 2007
  • September 2007
  • August 2007
  • July 2007
  • June 2007
  • May 2007
  • April 2007
  • March 2007
  • February 2007
  • January 2007
  • December 2006
  • November 2006
  • October 2006
  • September 2006
  • August 2006
  • July 2006
  • June 2006
  • May 2006
  • April 2006
  • March 2006
  • February 2006
  • January 2006
  • December 2005
  • November 2005
  • October 2005
  • September 2005
  • August 2005
  • July 2005
  • June 2005
  • May 2005
  • April 2005
  • March 2005
  • February 2005
  • January 2005
  • December 2004
  • November 2004
  • October 2004
  • September 2004
  • August 2004
  • July 2004
  • June 2004
  • May 2004
  • April 2004
  • March 2004
  • February 2004
  • January 2004
  • December 2003
  • November 2003
  • October 2003
  • September 2003
  • August 2003
  • July 2003
  • June 2003
  • May 2003
  • April 2003
  • March 2003
mattberther.com © 2003 - 2010