Uploading Files and Images with Rails File_Column (FileColumn plugin)
File_column is a plugin for the Ruby on Rails framework that enables easy uploading of files, especially images.
Suppose you have a list of users, and you would like to associate a picture to each of them. You could upload the image to a database, or you could use file_column for simple storage to the file system.
Let‘s create our database first, generate a migration (if you‘re not using migrations yet you are missing out!) and add
The FileColumn module allows you to easily handle file uploads. You can designate
one or more columns of your model’s table as “file columns”.
For this example, we’ll add only one, and call it “picture”.
Here is the migration/ table layout.
create_table "users" do |t|
t.column "name", :string
t.column "picture", :string
end
Now in your User class, just add the file_column method, and give it the name of your file_column (picture).
class User < ActiveRecord::Base
file_column :picture
end
Now just open up your existing user form, and edit it so it looks like the following:
<p><label for="user_picture">Picture</label><br/>
<%= file_column_field "user", "picture" %></p>
We‘ll need to set the form to multipart, so that the picture will actually be sent as well.
For my Create View
This makes a new user, and allows an image upload.
<%= form_tag( { :action => 'create' }, :multipart => true ) %>
<p><label for="user_name">Name</label><br/>
<%= text_field 'user', 'name' %></p>
<p><label for="user_picture">Picture</label><br/>
<%= file_column_field "user", "picture" %>
<%= submit_tag "Create" %>
</form>
For my Update View
This allows an existing user to add or update an image.
<%= start_form_tag({:action => 'update', :id => @user}, :multipart => true) %>
<p><label for="user_name">Description</label><br/>
<%= text_field 'user', 'name' %></p>
<p><label for="user_picture">Picture</label><br/>
<%= file_column_field "user", "picture" %>
<%= submit_tag 'Edit' %>
</form>
Validating File Size for file_column
class User < ActiveRecord::Base
file_column :picture
validates_filesize_of :picture, :in => 50.kilobytes..100.kilobytes
end
More examples:
validates_filesize_of :field, :in => 0..100.megabytes
validates_filesize_of :field, :in => 15.kilobytes..1.megabyte
validates_file_format_of :field, :in => ["gif", "png", "jpg"]
validates_file_format_of :field, :in => ["image/jpeg"]
More File_Column Documentation
modified from the File_Column source.
Now, by default, an uploaded file “test.png” for a user object with primary key 42 will
be stored in in “public/user/picture/42/test.png”. The filename “test.png” will be stored
in the record’s “picture” column. The “entries” table should have a +VARCHAR+ column
named “picture”.
After calling “file_column :picture” as in the example above, a number of instance methods
will automatically be generated, all prefixed by “picture”:
* User#picture=(uploaded_file): this will handle a newly uploaded file
(see below). Note that
you can simply call your upload field “user[picture]” in your view (or use the
helper).
* User#picture(subdir=nil): This will return an absolute path (as a
string) to the currently uploaded file
or nil if no file has been uploaded
* User#picture_relative_path(subdir=nil): This will return a path relative to
this file column’s base directory
as a string or nil if no file has been uploaded. This would be “42/test.png” in the example.
* User#picture_just_uploaded?: Returns true if a new file has been uploaded to this instance.
You can use this in your code to perform certain actions (e. g., validation,
custom post-processing) only on newly uploaded files.
You can access the raw value of the “picture” column (which will contain the filename) via the
ActiveRecord::Base#attributes or ActiveRecord::Base#[] methods like this:
user[’picture’] # e.g.”test.png”
Storage of uploaded files
For a model class +User+ and a column +picture+, all files will be stored under
“public/user/picture”. A sub-directory named after the primary key of the object will
be created, so that files can be stored using their real filename. For example, a file
“test.png” stored in a User object with id 42 will be stored in
public/user/picture/42/test.png
Files will be moved to this location in an +after_save+ callback. They will be stored in
a temporary location previously as explained in the next section.
By default, files will be created with unix permissions of 0644 (i. e., owner has
read/write access, group and others only have read access). You can customize
this by passing the desired mode as a :permissions options. The value
you give here is passed directly to File::chmod, so on Unix you should
give some octal value like 0644, for example.
Handling of form redisplay
Suppose you have a form for creating a new object where the user can upload an image. The form may
have to be re-displayed because of validation errors. The uploaded file has to be stored somewhere so
that the user does not have to upload it again. FileColumn will store these in a temporary directory
(called “tmp” and located under the column’s base directory by default) so that it can be moved to
the final location if the object is successfully created. If the form is never completed, though, you
can easily remove all the images in this “tmp” directory once per day or so.
So in the example above, the picture “test.png” would first be stored in
“public/user/picture/tmp/
“public/user/picture/
This temporary location of newly uploaded files has another advantage when updating objects. If the
update fails for some reasons (e.g. due to validations), the existing picture will not be overwritten, so
it has a kind of “transactional behaviour”.
Additional Files and Directories
FileColumn allows you to keep more than one file in a directory and will move/delete
all the files and directories it finds in a model object’s directory when necessary.
As a convenience you can access files stored in sub-directories via the +subdir+
parameter if they have the same filename.
Suppose your uploaded file is named “vancouver.jpg” and you want to create a
thumb-nail and store it in the “thumb” directory. If you call
picture(”thumb”), you
will receive an absolute path for the file “thumb/vancouver.jpg” in the same
directory “vancouver.jpg” is stored. Look at the documentation of FileColumn::Magick
for more examples and how to create these thumb-nails automatically.
File Extensions
FileColumn will try to fix the file extension of uploaded files, so that
the files are served with the correct mime-type by your web-server. Most
web-servers are setting the mime-type based on the file’s extension. You
can disable this behaviour by passing the :fix_file_extensions option
with a value of +nil+ to +file_column+.
In order to set the correct extension, FileColumn tries to determine
the files mime-type first. It then uses the +MIME_EXTENSIONS+ hash to
choose the corresponding file extension. You can override this hash
by passing in a :mime_extensions option to +file_column+.
The mime-type of the uploaded file is determined with the following steps:
1. Run the external “file” utility. You can specify the full path to
the executable in the :file_exec option or set this option
to +nil+ to disable this step
2. If the file utility couldn’t determine the mime-type or the utility was not
present, the content-type provided by the user’s browser is used
as a fallback.
Custom Storage Directories
FileColumn’s storage location is determined in the following way. All
files are saved below the so-called “root_path” directory, which defaults to
“RAILS_ROOT/public”. For every file_column, you can set a separte “store_dir”
option. It defaults to “model_name/attribute_name”.
Files will always be stored in sub-directories of the store_dir path. The
subdirectory is named after the instance’s +id+ attribute for a saved model,
or “tmp/
You can specify a custom root_path by setting the :root_path option.
You can specify a custom storage_dir by setting the :storage_dir option.
For setting a static storage_dir that doesn’t change with respect to a particular
instance, you assign :storage_dir a String representing a directory
as an absolute path.
If you need more fine-grained control over the storage directory, you
can use the name of a callback-method as a symbol for the
:store_dir option. This method has to be defined as an
instance method in your model. It will be called without any arguments
whenever the storage directory for an uploaded file is needed. It should return
a String representing a directory relativeo to root_path.
Uploaded files for unsaved models objects will be stored in a temporary
directory. By default this directory will be a “tmp” directory in
your :store_dir. You can override this via the
:tmp_base_dir option.