Caution! - Many of these posts are creepy-old in the Ruby on Rails world (before 1.0!)
The :author => Charles Abbott now blogs here

reverse! && a simple file Upload Class

2006-07-29   [ 7 comments ]

This should be a quick post. {"If", "I", "can", "help", "it!"}.reverse! = {"it!", "help", "can", "I", "If"}. =)

Well, there you have it. The simplicity of the reverse! method for arrays. This is especially great when you query the database for a group of records, then decide you need them in the reverse order. When might you actually need to do that? Well let me give you my example (and if anyone has a better way, let me kn0w):

@posts = Post.find(:all, :order => "id DESC", :limit => "25")
@posts.reverse!

In this situation I was pulling out the 25 of the newest posts (I ordered them by id descending - so the newest id would be at the top). Then before I printed the posts in the view I wanted to print the oldest at the top (like most message boards). So I just used the .reverse! method for arrays (you can read more about methods available to arrays by going to the Ruby Core Lib Reference).

Simple enough, so now on to the second part of this post - and perhaps the most enjoyable - a working Model that can help in simple file uploading. I may have already given snippets from this model, but I think it deserves a full feature:

class Upload < ActiveRecord::Base

def upload(file,directory="/your/directory/here")
  @file = file
  @directory = directory
  @extension = get_extension(@file)
  return save_file
end

def get_extension(file)
  return file.original_filename.to_s.split(".")[1]
end

def get_original(file)
  return file.original_filename.to_s
end

def save_file
   if @file.path
    @time_now = Time.now.to_i
    FileUtils.mv(@file.path, Dir.getwd << @directory << @time_now.to_s << "." << @extension)
    return @time_now.to_s << "." << @extension
  else
    return "File Not Uploaded"
  end
end

end

Instead of explaining how everything works, let me just give you the rest of the picture and a quick example how I used it in my controller to save files.

My database table:

CREATE TABLE `uploads` (
`id` int(11) NOT NULL auto_increment,
`oldname` varchar(255) NOT NULL default '',
`newname` varchar(255) NOT NULL default '',
`directory` varchar(50) NOT NULL default '',
`user_id` varchar(50) NOT NULL default '',
PRIMARY KEY (`id`)
);

And now my controller snippet (expecting a file passed in the params[:file])...:


if params[:file]
  @upload = Upload.new
  @upload.newname = @upload.upload(params[:file])
  @upload.oldname = @upload.get_original(params[:file])
  @upload.directory = "/your/directory/here/"
  @upload.user_id = session[:user]
  @upload.save
  flash[:notice] = "File Uploaded"
else
  flash[:notice] = "File Not Uploaded"
end

That is it. You can use this Model to help you upload and save files to a folder on your site. Then store some important file tracking data to your database. Not first class material, but it works - and for a ruby / rails beginner that is a bit rough around the edges still - it will suffice. I plan on refining it further, and I would like to add more features - but that is for another day!

:author => "Charles Abbott"
Ruby and Rails - Programming Euphoria
 


sgoodwin said:

Thanks much, your post was very informative and helped me out on my own project.

2006-08-02 14:32:59 UTC

Charles said:

You are most welcome, glad it helped!

2006-08-03 17:30:37 UTC

Charles said:

A note - Lightty behind my Apache server doesn't play nice with Dir.pwd or gwd Ruby methods.

(This only pertains to those people using Lighttpd proxied behind Apache2 - as my post on Aug-8-2006 discusses)

I had problems moving data from my /tmp directory to the working directory of my Rails app.

The reason? -- This setup caused my File.Mv and gwd commands do something like this:

/tmp/CGI00021.tmp -> //uploads/images/newfile.png

Notice the // -- it dropped the full directory path to the file (/home/www/www.forthecode.com/web/uploads/...)

My quick fix was hardcoding the full path in my model. Once I get some more time to debug this problem I'll write up a more complete solution.

2006-08-17 21:16:19 UTC

Charles said:

Again, as with the simple FileUtils.mv command, this will only work with files larger than 10k (as mentioned throughout the rails wiki).

2006-08-28 23:17:47 UTC

Bud said:

Beware! This file upload code won't always work. If the file is small (I think < 10k) then a /tmp/CGI* file is not created. Instead the file is kept in storage as an IOStream object. When this happens the only file class method that always works is File.read. File.path returns null. The file must be moved from storage using File.read's and File.write's (or similar) to the permanent file name.

2007-04-17 23:15:11 UTC

Charles said:

Thanks Bud for providing the solution. I never did get back to this after stating the same less than 10k problem (as noted in the comment above).

Life has kept me quite busy - plan on updating again soon.

2007-04-17 23:26:06 UTC

Bud said:

Actually, what made this so difficult to debug was that sometimes the smaller files were sent to /tmp! I think the decision to keep the data in core depended on the results of a malloc at the time of the upload.

2007-04-19 14:35:29 UTC

What?

Who?              Link?



Frameworks Good or Bad?   :date => "2007-10-06"
Where is ForTheCode.com Going?   :date => "2007-09-23"
Refactoring - Vital to Software Development   :date => "2007-09-23"
Mongrel Cluster a quick note - and extra notes   :date => "2007-05-20"
Linux Mongrel and Rails   :date => "2007-05-15"
form_remote_tag revisited   :date => "2007-01-07"
How To: Ubuntu 6.10 Edgy on Rails part 3   :date => "2006-12-30"
How To: Ubuntu 6.10 Edgy on Rails part 2   :date => "2006-12-24"
How To: Ubuntu 6.10 Edgy on Rails   :date => "2006-12-22"
verify ... 5.times do cycle   :date => "2006-09-25"
country_select, country_options_for_select, mail_to   :date => "2006-09-05"
Generate and Send Email in Rails   :date => "2006-08-26"
FDF Model, gsub, and send_data   :date => "2006-08-18"
Active Directory Authentication with acts_as_authenticated   :date => "2006-08-17"
Apache2 proxy with Lighttpd - FastCGI for Rails   :date => "2006-08-08"
reverse! && a simple file Upload Class   :date => "2006-07-29"
send_file - a link to download a file   :date => "2006-07-24"
Environments (production, development, test) and cache_pages   :date => "2006-07-04"
.class .methods .instance_variables   :date => "2006-06-14"
select_tag :multiple => true   :date => "2006-06-01"
FileUtils, action_controller rescues   :date => "2006-05-20"
file_field_tag, File.size, File.path, FileUtils.mv   :date => "2006-05-15"
javascript_include_tag, stylesheet_link_tag   :date => "2006-05-02"
submit_to_remote, form_remote_tag, script.aculo.us   :date => "2006-04-30"
periodically_call_remote, simple_format   :date => "2006-04-26"
observe_field - Ajax!   :date => "2006-04-21"
h method, TextHelper, sanitize(), strip_tags()   :date => "2006-04-15"
Rails API :My API [.count(), link_to, text_area :size]   :date => "2006-04-13"
Rails - HTML Select Tag   :date => "2006-04-05"
Pruning Old Sessions   :date => "2006-03-21"
If Elsif Else, and Searching Too!   :date => "2006-03-17"
SHA1 - A quick update   :date => "2006-03-15"
Initialized! good, Authorized? Great! part 2   :date => "2006-03-11"
Initialized! good, Authorized? Great!   :date => "2006-03-08"
Forms and Routing in RoR   :date => "2006-03-06"
My First RoR Post !   :date => "2006-03-05"