File upload


#1

This is probably me having an issue with the mvc way of living… .I’m
used to perl/php scripting…

I’ve got a photo blog I’m making… and in past iterations of this
website, I’d just name the photos after the id of the entry. For
instance:

/photos/id.jpg
/photos/id_thumb.jpg

However, I’m having trouble finding an easy way to do this with rails.

Everywhere I read either has an example of how to upload the file
directly into a database, or to use file_column. While file_column
looks nice and easy, it kind of bugs me that I’d have to create two
columns in my table to support the ability to upload a file… if I
have to do this, then I will, but I was curious if there is any easy way
to do this.

The only possibility I found was here:
http://wiki.rubyonrails.com/rails/pages/HowtoUploadFiles

However, there were a couple of things I wasn’t sure on:

  1. in the view:

What is [picture] a reference to? this isn’t being stored in the
database… is it just so we can access it with the person class?

  1. The use of file.open… I haven’t had much luck finding
    documentation on all the options…

File.open(“pictures/#{person[‘name’]}/picture.jpg”, “w”) { |f|
f.write(person[‘picture’].read) }

I’d really appreciate any help or suggestions.
Thanks
-tyler


#2

Hi tyler,

I got my fileupload running yesterday for our tumblelog:
http://pkk.kuebelreiter.net/

We wanted to upload files simply to /public/images, without any
database or sth like that.
And I didn’t want to associate my images to my Items.

So this is how i managed it:

Created an model image:
class Image
end

(it is emtpy yet, but I wanted to include a method for the override
problem, if a file already exists. But there were some troubles with
that…).

Then I generated a controller image in my admin-directory:

class Admin::ImageController < ApplicationController

def create
File.open(RAILS_ROOT +
“/public/images/#{@params[‘picture’].original_filename}”, “w”) { |f|
f.write(@params[“picture”].read) }
redirect_to :controller => ‘tumble’, :action => “new”, :bildpfad
=> @request.protocol + @request.host_with_port +
“/images/#{@params[‘picture’].original_filename}”
end

def new
@image = Image.new
end

end

And a template under admin/image/new.rthtml:

<%= form_tag({ :action => “create” }, :multipart => true) %>

Image:

<%= submit_tag 'upload' %>

<%= end_form_tag %>

Thats all :wink:
If you want to rename your files with your post.id, you have to
include the file-logic in your post-controller, to have the post.id.
But I think you get the idea.

You might also look into typo, there is a file-upload for each artikle.

HTH,
Beate


#3

tyler craft wrote:

This is probably me having an issue with the mvc way of living… .I’m
used to perl/php scripting…

mvc is a design pattern - can be implemented in any language [well
within reason]

looks nice and easy, it kind of bugs me that I’d have to create two
columns in my table to support the ability to upload a file… if I
have to do this, then I will, but I was curious if there is any easy way
to do this.

Do you want to store the image on the disk or in a database?

The only possibility I found was here:
http://wiki.rubyonrails.com/rails/pages/HowtoUploadFiles

However, there were a couple of things I wasn’t sure on:

  1. in the view:

What is [picture] a reference to? this isn’t being stored in the
database… is it just so we can access it with the person class?

Yes this assumes that there is an object called person [likely an
instnance of ActiveRecord] that has an attribute called picture [which
would most likely be a BLOB in a database somewhere] - to remove the
OOP, you could do this:

Then access in your controller with: @params[‘picture’]

  1. The use of file.open… I haven’t had much luck finding
    documentation on all the options…

http://corelib.rubyonrails.org/classes/File.html

File.open(“pictures/#{person[‘name’]}/picture.jpg”, “w”) { |f|
f.write(person[‘picture’].read) }

the File.new and File.open methods are essentially the same thing
[expect open allows for an included block, i.e the {|f|… bit] - whats
confusing is that you have to ‘open’ a file to create it [it actually
makes sense if you got a deep understanding of how file systems work,
but…] - f.write is an input stream for the file, picture.read is an
output stream for the incoming file, i.e. it is read to a write buffer…
this is for writing to a disk btw and not for a database… clarify
which one youre attempting to do.


#4

Thanks for the responses.

To clarify, I am simply wanting to save the file to disk, not in a
database.

So, for an example, in my admin/photo view, I’d have this:

Then, in my admin/photo controller would I then call a function in the
photo model and have this code:

File.open(“photos/#{valuePassedIn}.jpg”, “w”) { |f|
f.write(@params[‘picture’].read) }

Thanks again!
-tyler


#5

FileColumn only uses one field, a :string in migrations parlance, i.e.
varchar in typical SQL. In the db it stores the filename of the uploaded
file. If you have that field and

file_column :field_name

in the model, you’re off and running.

tyler craft wrote:

This is probably me having an issue with the mvc way of living… .I’m
used to perl/php scripting…

I’ve got a photo blog I’m making… and in past iterations of this
website, I’d just name the photos after the id of the entry. For
instance:

/photos/id.jpg
/photos/id_thumb.jpg

However, I’m having trouble finding an easy way to do this with rails.

Everywhere I read either has an example of how to upload the file
directly into a database, or to use file_column. While file_column
looks nice and easy, it kind of bugs me that I’d have to create two
columns in my table to support the ability to upload a file… if I
have to do this, then I will, but I was curious if there is any easy way
to do this.


#6

Steve K. wrote:

FileColumn only uses one field, a :string in migrations parlance, i.e.
varchar in typical SQL. In the db it stores the filename of the uploaded
file. If you have that field and

file_column :field_name

in the model, you’re off and running.

But what if I want multiple photos? For instance, a small/medium/large?
Would I need three extra columns?

…I should be able to have it just name the file off the id and just
through the images into a small/medium/large folder.


#7

If you want multiple versions of the same image, all you do is install
the RMagick gem or ImageMagick on your machine(s) and in your model you
can then say something like

file_column :field_name, :magick => {:versions =>
{ “thumb” => “80x60”, “small” => “150x120”, “medium” => “250x200”,
“large” => “640x480” }}

and poof! You have multiple versions of the image all generated, named
and saved automatically. Yes, there’s also syntax for constraining one
axis and scaling the other proportaionally. And to display the thumbnail
of, for instance, @photo.image, you’d then simply say

<%= image_tag url_for_file_column “photo”, “image”, “thumb” =%>

As for multiple distinct images in the same table row, you simply have a
file_column declaration for each one in the model:

Class House < ActiveRecord::Base
file_column :front_view, :magick => {:versions => { “thumb” =>
“80x60” }
file_column :floorplan
file_column :kitchen_photo
end

And of course each of those can have all the resized or manipulated
versions you want.

The file_column docs could use somefleshing out, especially the README.
:wink:

tyler craft wrote:

Steve K. wrote:

FileColumn only uses one field, a :string in migrations parlance, i.e.
varchar in typical SQL. In the db it stores the filename of the uploaded
file. If you have that field and

file_column :field_name

in the model, you’re off and running.

But what if I want multiple photos? For instance, a small/medium/large?
Would I need three extra columns?

…I should be able to have it just name the file off the id and just
through the images into a small/medium/large folder.


#8

Beate P. wrote:

Hi tyler,

I got my fileupload running yesterday for our tumblelog:
http://pkk.kuebelreiter.net/

We wanted to upload files simply to /public/images, without any
database or sth like that.
And I didn’t want to associate my images to my Items.

So this is how i managed it:

Created an model image:
class Image
end

(it is emtpy yet, but I wanted to include a method for the override
problem, if a file already exists. But there were some troubles with
that…).

Then I generated a controller image in my admin-directory:

class Admin::ImageController < ApplicationController

def create
File.open(RAILS_ROOT +
“/public/images/#{@params[‘picture’].original_filename}”, “w”) { |f|
f.write(@params[“picture”].read) }
redirect_to :controller => ‘tumble’, :action => “new”, :bildpfad
=> @request.protocol + @request.host_with_port +
“/images/#{@params[‘picture’].original_filename}”
end

def new
@image = Image.new
end

end

And a template under admin/image/new.rthtml:

<%= form_tag({ :action => “create” }, :multipart => true) %>

Image:

<%= submit_tag 'upload' %>

<%= end_form_tag %>

Thats all :wink:
If you want to rename your files with your post.id, you have to
include the file-logic in your post-controller, to have the post.id.
But I think you get the idea.

You might also look into typo, there is a file-upload for each artikle.

HTH,
Beate

I used this code, after runs this programme the images are uploaded into
the images folder, but If iam trying to open uploaded images, those are
opened but overlapped (I mean to say that not as the original image)
with some other images. So plz help me out in uploading as the original
image.

    and another thing is, I used this file tag in a form, after 

submit in the controller, it displayes an error as original_filename
undefined method.
what I have to do.

Thanks in advance
Surekha.Matte


#9

this is the code I ended up using. I have a form that has an image
submit button on it, and when i update it, I run this code:

if @photo.update_attributes(params[:photo])
if @params[“thumbnail”].size != 0
File.open("#{RAILS_ROOT}/public/photos/#{@photo.id}_thumb.jpg",
“wb”) { |f| f.write(@params[“thumbnail”].read) }
end
end