Adding pictures (continued)

OK – so yesterday i got photos working in the other photo_holder app, and more importantly got my head (mostly) around what it’s actually doing. First thing today is to get that into newspipe.

There’s a slight model change required to picture – we need to change the ‘blob’ field (for binary_data) to longblob – looking at photo_holder, it can only store the first few hundred k of any image, which isn’t anywhere near enough. Changing it to longblob in the db fixed it, so i just need to find out the rails word for ‘longblob’.

Found this useful bit of info:

In MySQL 4.1 and above, you can specify the length on a blob or text by using size. It’ll automatically expand to the right type. Example:

create_table :files do |t|
  t.column :data, :binary, :null => false, :size => 400000
end

So, i’ll do a migration to drop the binary_data column and replace it with another (which i’ll just call data actually) which is bigger. I’ll give it a limit of 5 meg, that should be enough for any typically sized jpg. While i’m at it, i’ll do the same for movies but give a limit of 500 meg. Need to remember to put these limits into validations in the model.

Hmm…the migration seemed to run ok but doesn’t seem to have changed the db. Ah wait – i’ve still got my development database set to that test one i set up yesterday to check my migrations were all in order.

Just had some problems in eclipse – found out that when i did the import of newspipe yesterday i didn’t set it up to run in the same folder properly (which was why my breakpoints weren’t working – i was putting them in the originals and the copies were running). Deleted the project, re-created it and this time set it up to work out of the original folder. So now i can debug with breakpoints, and i’m happily working in eclipse now, which is a bit nicer and definitely more professional.

That also means i’ve got no excuse for not doing unit tests 🙂 Will cover that later though.

For now – i’ve got the new version of the ‘new_picture’ form in and working. Next i need to add that method to the picture model and then change the create_picture action.

Done those – seems to have worked. Next i just need to add a render_picture method which renders the picture to the browser. Then, i can add a line to ‘edit_story’ and ‘show_story’ to output the pics. Here goes.

Worked first time! Amazing.

Having said that, eclipse just crashed trying to render a large picture and froze my browsers out until i killed the process. That’s not very good. I’ll try again.

Hasn’t crashed this time but it’s R E A L L L Y S L O O O oh wait, it has crashed again. When it crashed, it seemed like my HD went into overdrive, and according to task manager my cpu usage was also at 100%. How does that happen? Solid IO and solid CPU? Seems crazy. Let’s try running it the oldschool way, with a command line mongrel_rails server. uh oh – mongrel’s complaining. I bet the server eclipse started is still running.

can’t see anything obvious in task manager’s process bar. Killed a few things anyway. No joy. Tried mongrel_rails stop but it doesn’t seem to think it’s running. Argh.

Going to reboot. What a pain in the ass. Ah well, get a chance to read some more of “Surely you’re joking, Mr Feynman”.

OK, back again.  Running oldschool now, seems fine.  EXCEPT that there’s a problem with the pictures – i’m still only getting some of the picture – at a rough guess, about 80-100k of it.   The photo_holder app had this problem until i went into the DB and changed the type from ‘blob’ to ‘longblob’.  Putting the size in the migrate should have made a field to hold big enough blobs but it clearly hasn’t worked.

Actually, thinking about this some more, i probably shouldn’t put pictures in the database at all – i should put their id and details in the database, then save the picture in an app folder with the name renamed to id_number.jpg or whatever.  That would be smarter.  I can add save and load methods to the picture model.  This will definitely be better for movies as well, where i really don’t want to be pulling 50 meg files out of a database.   Putting a thumbnail in the db should be fine though.

So, the new plan for pictures is to

  • take the uploaded image
  • rename it with @picture.id and save it somewhere
  • reduce it to a thumbnail (keeping the same name)
  • put the thumbnail into the db

Then, it will be the thumbnail that’s displayed on the edit_story and show_story pages, but the thumbnail and title act as a link to show the full-sized picture.  Or, maybe i just show the full sized picture on those pages.  Either way, saving a thumbnail seems like a good idea.  Initially, let’s not worry about thumbnails and try to just save and retrieve the picture – i can go back to displaying just the title on the edit page.

So – i need to do a migrate to drop the data fields altogether.  Then, edit the model so that it doesn’t save into the data field., but holds onto the data instead.  I just did this by making it write into an attribute of the object that doesn’t have a corresponding db field :”file_data”.  Then, i call a write_to_disc method from the controller, which i’ll need to add now to the model.

OK – this is the Picture model now:

class Picture < ActiveRecord::Base
belongs_to :story
belongs_to :user

validates_presence_of :title

attr_accessor :file_data

def picture_file=(input_data)
#unless params[:photo].blank?
# @photo.update_attributes(params[:photo])
#end
self.filename = input_data.original_filename
self.content_type = input_data.content_type.chomp
self.file_data = input_data.read
end

def write_to_disc
#save the picture to newspipe/data/pictures with the name ‘#{self.id}.extension’
new_filename = “#{self.id}.#{self.content_type.split(“/”).last}”
if self.file_data.write(“C:/code/InstantRails/rails_apps/newspipe/data/pictures/#{new_filename}”)
return true
else
return false
end
end

end

This isn’t working – when i call write, it crashes and complains because i’m calling ‘write’ on a string.  But i’m setting file_data equal to the return from read, which i thought was data.  It makes sense to get something with ‘read’ and then call ‘write’ on it…but it’s not working.

As an experiment i tried setting file_data equal to the whole input_data object, but i think that’s just a hash.  It doesn’t save anything anyway, although it is called fine.

Had a recommendation off a forum to set file_data equal to a TempFile object, using input_data.  Trying this with

self.file_data = ::TempFile.new(input_data)

but get back an error saying ”

uninitialized constant TempFile

I’ve got

require “tempfile”

at the top of the model file…

Tried something else and have cracked it!  YAY.  I’m using File.open, which if you give it the params “wb” means “open for writing as a binary”:

File.open(path, “wb”) { |f| f.write(self.file_data) }

Very pleased.  Currently ‘path’ is made up of a hard coded rails location and local path, plus the autogenerated file name.

Just improved this by using RAILS_ROOT which returns the location of the newspipe folder (in a really roundabout way, by going in and out of config a few times!)

So, my model methods are now as follows:

 def picture_file=(input_data)
self.filename = input_data.original_filename
self.content_type = input_data.content_type.chomp
self.file_data = input_data.read
end

def write_to_disc
#save the picture to newspipe/data/pictures with the name ‘#{self.id}.extension’
new_filename = “pic#{self.id}.#{self.content_type.split(“/”).last}”
File.open(“#{RAILS_ROOT}/data/pictures/#{new_filename}”, “wb”) { |f| f.write(self.file_data) }
return true
end

Next, i want to

  • retrieve the picture from the data folder, and show it on the show_picture page.
  • make a thumbnail of the picture and put the thumbnail into the database.  Or maybe it would be best to just save it on the hd as well and keep the db access fast and minimal.

Trying to install rmagick, which allows lots of easy image manipulation (such as displaying thumbnails) and it’s just been a constant struggle.  Got it installed but mongrel_rails complains about a missing dll when it tries to load.  gah.  Stopping now and going to the pub.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s