Ruby on Rails
HowToUseFileColumn

This is straight from the file_column website:

Just create a database column to store the filename:

add_column :entry,:image,:string

Then make the “image” column ready for handling uploaded files…

class Entry < ActiveRecord::Base file_column :image end

… generate file fields that keep uploaded images during form redisplays to your view:


    <%  @entry = Entry.find(params[:id]) %>
    <%= file_column_field "entry", "image" %>
   

… and display uploaded images in your view…


    <%  @entry = Entry.find(params[:id]) %>
    <%= image_tag url_for_file_column("entry", "image") %>
   

It’s just as easy! Why should it be any more difficult for a Rails application?

So what about the RMagick integration? Have a look:

To resize every uploaded image to a maximum size of 640×480, you just have to declare an additional option.

class Entry < ActiveRecord::Base file_column :image, :magick => { :geometry => “640×480>” } end

You can even automatically create versions in different sizes that have nice filenames…

class Entry < ActiveRecord::Base file_column :image, :magick => { :versions => { “thumb” => “50×50”, “medium” => “640×480>” } } end

… and display them in your view:


<% @entry = Entry.find(params[:id]) %> <%= image_tag url_for_file_column(@entry, "image", "thumb") %>


NOTE: Your form has to be multipart/form-data, which is done like this:

<%= form_tag( { :action => 'do_image_upload' }, :multipart => true ) %> 

and not like this:

<%= form_tag( :action => 'do_image_upload', :multipart => true ) %> 

and not like this, either:

<%= form_tag { :action => 'do_image_upload' }, :multipart => true  %> 

Thanks to Greg @
http://destiney.com/blog/rails-form-tag

Note by a coward:
Actually you should do none of these, according to the docs. There should not be any “=”. The real way should be (according to all I know):


<% form_tag( {:action=> 'do_image_upload' }, :multipart=> true ) do %>

……..

<% end %>.

And don’t forget the word “do”!!
One thing remains a mystery to me: How to use a named form (which you may need to do if you have more than one form on a page) without using the deprecated form


<%= start_form_tag( {:action => 'do_save_all' }, {:name=>"my_2nd_form", :id=>"my_2nd_form", :multipart => true}) %>

………..

<%= end_form_tag %>.


I am working with Rails 1.2.3 and Ruby 1.8.6.


Using Amazon S3 with file_column

We hacked file_column to support storing to Amazon S3. It’s not perfect, but should be a good start for anyone that wants it:

Amazon S3 support for file_column

Scott Persinger


A few tips from the Rails mailing list regarding the configurability of the file_column plugin

You can set the storage base path with the :store_dir option:

file_column :image, :store_dir => “foobar”

As for the path prefix, you could dynamically redefine the method FileColumn::PermanentUploadedFile#relative_path_prefix somewhere in your application code. The default implementation is pretty straight-forward

def relative_path_prefix @instance.id.to_s end

so just replace ‘id’ with ‘username’


In my case, I wanted my images to be stored in a folder with the login field of my User object. Problem is, my image column is in another table called Profile. Since each User has_many Profiles and Profile belongs_to User, I couldn’t just change @instance.id to @instance.login, because in my case @instance is my Profile object and not my User object.

To work around this, I had to use the Profile.user_id value to find the proper User object and get the User.login field. Here is my code which I placed at the bottom of my environment.rb file:

module FileColumn
  class PermanentUploadedFile
    def initialize(*args)
      super *args
      
      user = User.find(@instance.user_id) # change
      @dir = File.join(store_dir, user.login.to_s) # change
      @filename = @instance[@attr]
      @filename = nil if @filename.empty?
    end
    
    def relative_path_prefix
      user = User.find(@instance.user_id) # change
      user.login.to_s # change
    end
  end
end

Probably not the most efficient code, but it works for me. If there is a cleaner way to do this, please update this Wiki.

Thanks to Gerret from the mailing list for his help.


just a note about using url_for_file_column inside an iteration

url_for_file_column(@entry, “image”, "thumb")
<% for entry in @entries %> <%= <b style="color:black;background-color:#ffff66">url_for_file_column</b>(entry, "image") %> <% end %>

When using url_for_file_column in a partial you need to assign the local variable into an instance variable before calling the method.

<% @item = item -%>

I think you mean:
<% item = @item -%>


Also try this if above does not work for url_for_file_column in a partial:

First go into your file_column_helper.rb file and change the following code:
_"rails_app\vendor\plugins\file-column\lib\file_column_helper.rb"_

Before:


def url_for_file_column(object_name, method, suffix=nil) object = instance_variable_get("@#{object_name.to_s}") ...


After:


def url_for_file_column(object_name, method, suffix=nil) object = case object_name when String, Symbol instance_variable_get("@#{object_name.to_s}") else object_name end ...

Then change your partial code to this:
_partial.rhtml


<% for post in @post %> <%= link_to (image_tag(url_for_file_column(post, "image", "square")))%> ...

Don’t forget to restart your server after editing the "/filecolumn_helper.rb"_ file


(by file_column author Sebastian Kanthak)
because url_for_file_column expects the model in an instance
variable, as stated in the docs as well. This is a rails convention
that you’ll find in other helpers as well, for example text_field. I
simply followed this convention, but lots of people seem to have
trouble with it. Perhaps, I’ll come up with something else…


Uploading files to a directory outside of the RAILS_ROOT

Has anyone had any luck using FileColumn to upload files to a location outside the RAILS_ROOT?


Note: although you may find it obvious, it’s not explicitly mentioned in the docs that for file_column to work your DB table needs a text column (eg varchar(100) ) long enough to store the filename of the image file uploaded.

Re uploading files outside of the Rails root, if you look inside vendor/plugins/file_column/lib/file_column.rb about halfway down the file a long block of documentation begins. It describes there how to set custom storage locations:


 == 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/<randomkey>" for unsaved models.
  #
  # You can specify a custom root_path by setting the <tt>:root_path</tt> option.
  # 
  # You can specify a custom storage_dir by setting the <tt>:storage_dir</tt> option.
  #
  # For setting a static storage_dir that doesn't change with respect to a particular
  # instance, you assign <tt>:storage_dir</tt> 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
  # <tt>:store_dir</tt> 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 <tt>:store_dir</tt>. You can override this via the
  # <tt>:tmp_base_dir</tt> option.

Setting up file_column on windows machine to be able to auto-generate thumbnails

I had trouble getting this done following the various instructions from the diff apps, so i wanted to keep a record of how i got it working in the end. (NB: I’m a RoR/command line newbie so please correct/alter if this is a weird way of doing things.)

First install file_column by running the following from the command prompt:

ruby script/plugin install [ insert latest url from file_column site]

Get the most current url from the instructions on the file_column site.

Next you’ll need to install RMagick. RMagick is an interface between Ruby and the image manipulation applications, ImageMagick and GraphicsMagick. Conveniently, the windows download contains RMagick itself, as well as ImageMagick.

Download ‘rmagick-win32 x.x.x binary gem’ from the RMagick download page

Once downloaded use ‘cd’ to navigate to the newly downloaded directory containing the .gem file. Then run the following command (replacing the x’s with the correct version number):

gem install RMagick-win32-1.x.x-mswin32.gem

Once that’s done you need to run the following command (in the same directory) to finish the job:

postinstall.rb

Setting up my app

(I couldnt find a link to full documentation about file_column, pls edit and place link/instructions here)

Now the following directory should be present in your rails app myApp/vendor/plugins/file_column.

Decide which model you want to use to store the uploaded image info. Choose a field in that model and set its type to varchar or text so that it can contain long filenames.

Next: In my case i added this line to the .rb file for my model:

file_column :image, :magick => { :geometry => "640x480>",
      :versions => { "thumb" => "50x50"}
    }

This tells my app that the field ‘image’ in my model should be used to store filenames of uploaded images.

The versions array creates a resized copy of the image with the name ‘thumb’ in this case.

To write the form where users can upload images use something like the following to make sure the form is a multi-part type:

<%= form_tag({:action=>'create_art_image', :id=> @art_image}, :multipart => true)%>

Use something like the following line to add the file browse button (‘art_image’ is the name of the model holding the image information):

<%= file_column_field “art_image”, “image” %>

Inside the controller that handles the form submission the following line saves the record, and the image manipulations and storage are handled automatically:
art_image = ArtImage.new(params[:art_image])

By default the fullsize images get saved to:

myApp/public/[Model name]/[file_column field name]/[record id]/[image filename]

And the ‘thumb’ versions end up in:

myApp/public/[Model name]/[file_column field name]/[record id]/thumb/[image filename]

To display the thumbnails in my views i use:

<%= image_tag <b style="color:black;background-color:#ffff66">url_for_file_column</b>(@art_image, "image", "thumb") %>

—-

Gotchas

$HTTP["useragent"] =~ "^(.*MSIE.*)|(.*AppleWebKit.*)$" {
    server.max-keep-alive-requests = 0
  }

also: remember to update your schema !
The image that is upload get’s its filename stored in the models :image column (or whatever you call it).
So, make sure this is a varchar’ish field that can store the length of the file name.

—-

Putting all files under one subdirectory

I wanted all of my files to be stored under public/files. It took me a while to figure out I needed to pass the :root_path option to get it to save there, and the :web_root option to make the helpers build the correct url:


file_column :image, :web_root => "files/", :root_path => File.join(RAILS_ROOT, "public", "files")

Is there a better way to do this?


A note on creating square thumbnails

In the rdocs of the current version of filecolumn (0.3.1) there’s an example given of how to create square thumbnails using the MagickExtension commands, but for me that example didnt give the expected results (the ‘crop’ part seemed to be being ignored and the thumbnails kept the original images width/height ratio).

Adding the ‘!’ modifier to the size parameter for the thumbnail version gave me the expected result:

class ArtImage < ActiveRecord::Base
belongs_to :artwork

file_column :image, :magick => {:versions => {
      :thumb => {:crop => "1:1", :size => "50x50!", :name => "thumb"},
      :normal => {:size => "500x500>"}
      }
    }
end

(Also, incase other people were wondering; crop conveniently preserves the center of an image, removing space from the edges to reach the target width/height ratio).

More information about the geometry string here


How do I delete an entry in a file_column? Just delete the associated model. The file_column is just an annotation on a field in the model.

—But, what about if you didn’t create a new model just for the file_column uploads, but instead added a new column to an existing model? I don’t want to delete my entire user object, just the image files each user can upload via file_column…

Set the model’s filecolumn field to nil. Saving the model will delete the associated files._


How would one go about allowing the user upload multiple images at once?

A great resource for doing this can be found here: http://the-stickman.com/web-development/javascript/upload-multiple-files-with-a-single-file-element/

I adapted a version of the multiple file upload script(newest mootools version) so it works with filecolumn. Complete details and instructions can be found at:_
http://www.silverscripting.com/blog/2007/12/18/multiple-file-upload-with-rails-file_column-plugin-and-mootools/


Are there any plans to strip out RMagick?

It seems like RMagick causes a lot of headaches for people who want to use file_column. Are there any implementations of file_column without RMagick?

Using filecolumn without specifying thumbnail options should work without RMagick_


How to refresh file_column image if I want to change version parameters later on?

I asked this question on the Rails forum and the best reply quoted the Caboose site. I’ve repeated it here:

For a definition of:

class Attachments < ActiveRecord::Base file_column :asset, :magick => { :versions => { “thumb” => “50×50”, “medium” => “640×480>” } } end

Backup your attachments first, then open up script/console and…

Attachment.find(:all).each do |a| a.asset = File.open(a.asset) a.save end

I haven’t tested it, mind. I ended up writing a far heavier, more klunky script before I got the reply.

caboose

The caboose solution does not work as-is… a more complete solution can be found at how to regenerate file_column images

How to save the image width and height in the database

Put this in your create action:

image = Magick::Image::read(@entry.image).first
@entry.imagewidth = image.columns
@entry.imageheight = image.rows  

How do you clean up disk files when running tests?

Running Rails tests (unit, functional, etc., as well as selenium tests) will drop and reload test DB content, but they do not touch the disk files created by file_column.

What is the right way to handle this?

Your functional and integration tests don’t need to upload real files. file_column provides some mock objects for you to use in your tests. Have a look. http://opensvn.csie.org/rails_file_column/plugins/file_column/trunk/lib/test_case.rb


Processing images uploaded via file_column through a rmagick script

What is the proper way to upload an image to the filesystem, and save a version of the image that has (for example) been processed through the rmagick polaroid example?


Validation ignored?
I’m using the file_column plugin to upload a small avatar, but when I
do this:

@user.update_attribute("picture", params[:user][:picture])

… it completely ignores the validations I’ve set for the element
before:

validates_file_format_of :picture, :in => ["gif", "jpg", "png"]
validates_filesize_of :picture, :in => 1.kilobytes..100.kilobytes

I’m able to upload PDF’s, textfiles, etc., which is ofcourse rather
crappy. I’ve added this to my model, in case you’re wondering:

file_column :picture, :base_url => "images/people", :filename =>
"picture", :store_dir => "public/images/people/",
   :magick => {
    :size => '48x48!',
    :crop => '1:1',
    :versions => {
      :thumb => {:crop => "1:1", :size => "16x16!", :name => "thumb"}
    }
  }

Has anybody else experienced this problem?

Answer: update_attribute() is designed not to use validations. see the ActiveRedcord API doc. Try update_attribute*s* instead.


Error if .JPG instead of .jpg

I get error when uploading an image file with .JPG (capital JPG) extension.
If I change “JPG” to “jpg” in the file_column field and then submit the form, everything works fine.
How can I avoid this error?

Partial And Ugly Solution

I don’t have a fix to this, but I do have a very, very ugly workaround. I’m very green with Rails (and Ruby) and so took it upon myself as educational exercise into the bowels of someone else’s code. I added the code (in bold) after the line listed below in TempUploadFile#store_upload(file) in file_column.rb:


@filename = FileColumn::sanitize_filename(file.original_filename)
<b>@filename.downcase!</b>

It seems to do the trick – the file is stored in the file system and in the database with the lowercase name. Using lowercase file names gets around the problem. Of course, if your OS is case-sensitive and you’ve already upload another file that happens to be the same name (that is in lower case), you’re going to get into trouble.

I haven’t delved into this problem, but it seems to be an issue within FileUtils and its copying methods.




How to add file security?

How can I use file_column while still ensuring that only certain users are allowed to access files? If everything is stored in /public, then anyone can access it (if they know the file name or start url hacking). What I need is to be able to use authentication type controls to see if someone is authorized to download a file.

If it’s not stored in RAILS_ROOT/public – e.g. if it’s in RAILS_ROOT/s3kr1t_f1l3z :) – then it would need to get served somehow by the Rails app itself…?

What about defining a custom route in routes.rb which sends you thru some sort of authorization checker then serves the file? You wouldn’t have to modify filecolumn at all for that… but I don’t know if it’s possible… _

_This can be done by storing files in the database. This way, they will be served via a controller, so you can add all kinds of authorization you want. Check fleximage _


What If I want to just get the file name?

The filenames themselves are stored in the database, now, whenever I try to print the filename ONLY, for instance:

<pre> <%= artwork.file %> </pre>

returns a long path to the file when it used to give me just “blahblah.jpg”

How do I just make it act the way it used to?

- Try adding “_before_type_cast” to your column name. E.g.:

<pre> <%= artwork.file_before_type_cast %> </pre>


Having trouble when trying to download the file? Getting a route error?

It’s probably the problem with permissions. I edited the move_from function in file_column.rb to make it look like this (look at the first if statement):

<pre> def move_from(local_dir, just_uploaded) # create a directory named after the primary key, first unless File.exists?(@dir) FileUtils.mkdir(@dir) FileUtils.chmod_R 0755, @dir end # move the temporary files over FileUtils.cp Dir.glob(File.join(local_dir, "*")), @dir @just_uploaded = just_uploaded

# remove all old files in the directory FileUtils.rm(Dir.glob(File.join(@dir, "*")).reject! { |e| File.exists?(File.join(local_dir, File.basename(e))) }) end

Can someone with commit-rights to the trunk please add the :web_root option to the “official” documentation in this plugin? I’ve now spent 4 hours trying to fix it another way – and then realizes that there’s already an option.


Anybody got resizing of animated GIFs without losing the animations?
I found some links, but none work.


I’m somewhat of a rails newbie, and the validates_on* methods weren’t being found (assuming they were refactored/removed in rails 2). The new technique for validation that works for me is:
validates_format_of :attachment, :with => /^.*\.(pdf)$/i
validates_size_of :attachment, :within => 1.bytes..5000.kilobytes
The format example only accepts PDF files.



In init.rb
http://opensvn.csie.org/rails_file_column/plugins/file_column/trunk/init.rb
require ‘test_case’
must be removed. Because script/runner prints out so many messages.


Hello, I´m also kind of a newbie with RoR, I built a model where a user can have up to 5 images uploaded which are stored in the same model. I have a view which helps the user edit the information he is adding to his post. In this view I would like the user to be able to change the uploaded images (which up to now can be done without problems) and even delete one or two etc images without having to delete his entire posting.

I´ve been searching for this some days from now and havent found anything. I saw in one forum a guy who tried setting the database filename column for the record to “NULL” or "" and that did not work for the user so he had to build separate models the pictures, which I don´t want to do unless there is no other option.

I would appreciate any help. Thanks!