Thursday, April 26, 2007

Getting Your attachment_fu Back Out Of The Database

I have been busy the last few nights incorporating the brilliant Rails plugin called attachment_fu from Rick Olson aka technoweenie. If you do not know about attachment_fu, it is a complete solution to the problem of uploading image files attachments to include with your models.

First, I had to get past the initial hurdle of getting ImageScience and FreeImage correctly installed and working on my Mac. Despite the claims that Locomotive should have already had these in the bundle, I had to go thru a small process to get the prerequisites going.

I was then able to easily follow the careful instructions of Mike Clark, who has blogged at some length of how to get started with attachment_fu. In very short order, I had a working upload page, and another page displaying the automatically generated thumbnails. I was happily bragging to myself that "my attachment_fu has grown powerful, ha ha ha".

Then it occurred to me that using the :file_system option which stores uploaded files and thumbnails onto the web server's drive, typically into a special part of the "public" directory, was quick and easy, but not very scalable. Suddenly my attachment_fu is wimpy.

Luckily, attachment_fu supports the idea of "backends", which are code modules designed to communicate with the backend storage to be used for the images and thumbnails. The three provided backends are the file system, database, and Amazon's S3 storage. I decided that switching to the database storage was the best for my particular application. I changed the configuration option as described by Mike Clark, and ran my app expecting everything to just work...

Boom! Errors up the wazoo. OK, I wade in and discover that there is plenty of hidden away functionality in that plugin. First, the database storage backend requires an additional table called "db_files" not mentioned in mike clark's blog. The required additional migration is as follows:


t.column :db_file_id, :integer

create_table :db_files do |t|
t.column :data, :binary
end


You will need to add the "db_file_id" column to the table that stores your attachments. Then you need to create the "db_files" table to hold the actual binary data for the images and thumbnails.

I made the changes, ran the migration, and then I was able to upload the image. Almost there... However, I was shocked to see an error on the page that was supposed to display said image. Uh-oh!

It turns out that although the mechanism for displaying images which are stored in the file system or in S3 are exposed so they are web server accessible, the database storage engine is not yet fully implemented. Most importantly, the "public_filename" method is not there. So images get into the database, but there is no convenient way to display them.

At first I thought that I could use the "create_temp_file" method. However, a Ruby Tempfile deletes itself when it goes out of scope. Not the right thing, unless you don't mind images that disappear before they are actually displayed in the browser.

Anyhow, I went and after studying the code a bit, made a few changes to attachment_fu to provide better support. My solution was to add a method to the database backend to render the binary image data on the fly whenever it is requested.


def image_data(thumbnail = nil)
if thumbnail.nil?
current_data
else
thumbnails.find_by_thumbnail(thumbnail.to_s).current_data
end
end


To keep things nice and restful, I added support to my User controller to render the image when image format is requested:


def show
@user = current_user

respond_to do |format|
format.html # show.rhtml
format.xml { render :xml => @user.to_xml }
format.jpg do
picture = current_user.picture
image = picture.image_data(:thumb)
send_data (image, :type => 'image/jpeg',
:filename => picture.filename,
:disposition => 'inline')
end
end
end


Once this is all completed, displaying the image within a view is simple with a helper:


def user_thumbnail_tag(user)
image_tag("#{user_path(user)}.jpg")
end


And there you have it. The nice thing about this solution is you can deploy on multiple web servers behind a load balancer without concern. Thanks to the awesome power of attachment_fu...you have been warned.

Wednesday, April 25, 2007

Growing The Code

Kevin Barnes over at Code Craft has a cool posting comparing software development to gardening. I agree with him that it is a fantastic analogy!

It really rings true to me in a couple of fun ways:

  • Gardening cannot be done once and for ever. It takes constant work to keep it both healthy and tidy.

  • There is a big difference in both purpose and aesthetics within different gardens. Consider a typical traditional backyard garden vs. Noguchi Gardens. Or a small family farm vs. a large industrial combine. Each is in theory intended to fulfill a similar purpose, but does so in radically different ways.

  • Some people seem to have a knack for gardening, while others cannot help but kill even a hardy plant. And of course, the only way to tell if a gardener is any good, is to look at some gardens they have tended recently.


The problem with applying any real-world analogy to a virtual thing, is it will inevitably fall apart at some point. But this one is pretty sturdy at first glance.

Monday, April 16, 2007

Silverlight and Ruby?

Today, Microsoft announced their Silverlight technology platform. I will not bore you, kind reader, with yet another recap of what has already been written by so many others already.

However, there are a couple of curious details that have piqued my interest. John Lam, of RubyCLR fame, made an interesting comment on his blog earlier today about Silverlight:

This was a major reason why I moved my family to the other side of the continent...


Even more interesting, is a bit from Chinese news site CSDN, which is poorly translated here:

6, in addition, Silverlight designers and developers to provide a large number of development tools and development support. 对设计者来说,Expression Design和Expression Blend软件可以创建可重用界面,Expression Web使得在符合W3C标准的网站开发中可以使用XHTML、XML、XSLT、CSS以及ASP.NET等工具。To the designers, Expression and Expression Blend Design software can be re-established use interface Expression Web made in the development of the website with W3C standards can be used XHTML. XML, XSLT, CSS and ASP.NET tools. 对开发者来说,基于Visual Studio的Web开发支持包括ASP.NET AJAX在内的技术,并支持JavaScript,C#,VB,Ruby以及Python等多种开发语言。For developers, Visual Studio's Web-based support, including the technical AJAX ASP.NET and support JavaScript, C #, VB, Ruby and Python and other development languages.


So what is up? Is Ruby the programming language for Silverlight? Or at least one programming language option? Will dynamic languages take over the new desktop?

Tuesday, April 10, 2007

My New MacBook Pro Rocks For Rails Development

The last week or so I have been very busy playing with and setting up my new MacBook Pro. This is, in fact, my first post from it. After spending some time with it, I have to say that I am still extremely pleased! I have my Ruby on Rails environment all setup and working spendidly. I have my primary dev toolset CocoaMySQL, Locomotive, TextMate, and SVNx and now everything is pretty dialed in. I was able to grab one of my rails projects from my SVN repository, and run it successfully, after tweaking a few file permissions.

Wow, this baby can cook! Not just the temp, but the performance is great. I installed Parallels and couple versions of Windows XP for testing. It seems funny to me, having XP in one window, bash in another, and a stylish OSX app in a third. I know I could have done more with virtual OS stuff before I had this Mac, but now it's just so fun and easy!

Anyhow, now that I have come back to the Mac side, I sure feel a whole lot better! I guess you really CAN have it all nowadays...