File uploads and saving blobs to MySQL database

I’ve been having trouble trying to get uploaded images to save
correctly to a blob field in a MySQL database.

Here’s my form view

VIEW:

<% form_for(@user, :html => { :class => ‘edit’,:multipart => true })
do |f| %>

Picture <%= error_message_on(:user, :picture) %>

  <%= f.submit "Submit" %>

<% end %>

…which produces the correct form header, so I know multipart is
working:

Here’s my code for saving the picture to the db:

CONTROLLER:

if !params[:user][:picture].blank?
params[:user][:picture].rewind # Recommended to add
@user.picture = params[:user][:picture].read
end

In an irb console, I can see that params[:user][:picture].class ==
ActionController::UploadedStringIO

irb(#UsersController:0x7ee75580):006:0> params[:user]
[:picture].class
=> ActionController::UploadedStringIO

I can also see the binary blob of the file when I try and read it:

irb(#UsersController:0x7ee75580):003:0> @user.picture = params[:user]
[:picture].read
=> “GIF89aÈÈ÷\e>\032\036>\034!?"&>\032\036C\032\035H\035"E\036#
L\037(G\036)K\037&Q!%D"&M$)F$(M)-M$‘P"’[$Q$Y-S-Y,1F-1M,2U-
2Y26M14U26[6;S59]9?V:=]6=a;>b>B]>Ad?IcBE[FI]IM_BEdCGlFJeFIkIM
cILlFJqJNrMPeMQlNQqRUmSXl]\oSUsUXuZ]{^a}cd|fi|hj|^a\200ce\202fi\2
…(it’s long)…
270ÇMîrûÜèN·\272×Íîv>>ûÝð·\274çMïzÛûÞøÎ·\276\005\025\020\000;”

Once it’s saved into the db:

irb(#UsersController:0x7ee75580):005:0> @user.picture.class
=> String

But when I try to view the same image in the Rails view, it don’t
work. My co-worker uploaded several pictures to the blob field using
VB.net, and I can see his pictures just fine, but not mine.

Here’s my display code:

VIEW:

<%= image_tag("/users/picture?user_id=#{user.id}", :size => '60x60', :alt => "Picture") unless (user.blank? && user.picture.blank?) %> ==========

CONTROLLER:

def picture
user = User.find_by_id(params[:user_id])
send_data(user.picture)
end

Now, I can do something like:

File.open(“/c/rails/public/tmp-pic.jpg”, ‘wb’) do |f|
f.write params[:user][:picture].read
end

And I can open up tmp-pic.jpg and view it, which means the upload
works, and the reading works, but just not saving to the db…

I don’t think it’s a file-type problem (.gif, .jpg, .png) since I
tried all three types, and still nothing.
I assume it’s reading it and storing it as a string, instead of as a
blob, but not really sure about MySQL and how it handles that, if
that’s even the problem.

Any help would be greatly appreciated!

See the attachment_fu plugin for Rails. It will do this for you :slight_smile: Or
if
you want to know how to do it yourself, examine the source. It can
persist
to a file, a database, or S3.

http://svn.techno-weenie.net/projects/plugins/attachment_fu/

Yeah, I really didn’t want to go that route, this should be a real
simple thing, I shouldn’t need a whole bloated plugin to just save a
picture to a blob field. From what I can see, attachment_fu also does
the rewind and read commands, that’s where I got the ideas. How do I
get it back into a blob from a string? since I think thats my
problem…

I’m not sure, honestly. I know the plugin works. It’s far from bloated,
and
it’s already got tests written to prove it works, hich saves you time.
I
attempted to do this one time and it wasn’t worth my time to figure it
out.

Perhaps someone else reading this can tell you what’s going on.

Yeah, I really didn’t want to go that route, this should be a real
simple thing, I shouldn’t need a whole bloated plugin to just save a
picture to a blob field. From what I can see, attachment_fu also does
the rewind and read commands, that’s where I got the ideas. How do I
get it back into a blob from a string? since I think thats my
problem…

Coming into this late, but this is what I do (@the_user is exactly what
is
sounds like and is defined elsewhere):

view ---------------------------------------------------------------
<%= form_tag({:action => ‘upload_avatar’, :id => @the_user},
:multipart => true) %>
Please select an image to upload.


<%= file_field_tag :image_data %>
<%= submit_tag ‘Upload Avatar’ %>
<%= end_form_tag %>

controller ---------------------------------------------------------
def upload_avatar
avatar = Avatar.new(:user => @the_user)
avatar.image_data = params[:image_data]
avatar.save
flash[:avatar_errors] = avatar.errors.full_messages
redirect_to :action => ‘manage_avatars’
end

model (in a before
hooks)----------------------------------------------------

may be a string or a stringio

data = if image_data.respond_to?(:rewind)
image_data.rewind
image_data.read
else
image_data
end

img = GD2::Image.load(data)

unless img.width == IMAGE_WIDTH && img.height == IMAGE_HEIGHT
img.resize!(IMAGE_WIDTH, IMAGE_HEIGHT, true)
end

self.image_data = img.jpeg(75)

sql -------------------------------------------

| image_data | blob | YES | | NULL | |

My co-worker got this working using Philip’s code, which is pretty
much what I tried before. Actually, it’s exactly the same, rewind then
read. So maybe it was my localhost acting up and playing tricks on me.
I appreciate all you help, and I think we can call this one closed :slight_smile:

Summary - how it should work:

model (in a before
hooks)----------------------------------------------------

may be a string or a stringio

data = if image_data.respond_to?(:rewind)
image_data.rewind
image_data.read
else
image_data
end