Getting A Grip on GridFS
Update: This project is renamed and now actively developed as joint.
I know it is almost Christmas and your minds are beginning to turn to gifts and family, but hang with me for a few more minutes. My buddy Jon pointed me to Grip yesterday. I liked the idea but not all of the implementation. I’ve been doing some GridFS stuff lately so I decided to take some time and tweak it to be more what I need.
class Foo include MongoMapper::Document include Grip has_grid_attachment :image has_grid_attachment :pdf end image = File.open('foo.png', 'r') pdf = File.open('foo.pdf', 'r') foo = Foo.create(:image => image, :pdf => pdf) foo.image # contents read from gridfs for serving from rack/metal/controller foo.image_name # foo.jpg foo.image_content_type # image/png foo.image_size # File.size of the file foo.image_path # path in grid fs foo/image/:id where :id is foo.id
The main changes I made were to store name, size and content_type along with the path to the file. I also made it so those are assigned when the file is set so that they can be used in validations. Some other ideas I have for the plugin are adding image resizing with MojoMagick and common validations (much like most of the file upload plugins out there).
What I really like about Grip is its simplicity. A single, small file, an include, a call to has_grid_attachment, and you can start storing files. The great thing about working on this is it gave me some wonderful ideas for how to standardize the process of creating and declaring MongoMapper plugins.
I’ll be adding those to ideas to MongoMapper over the next few weeks as I get time and I think people are going to be stoked about what I’ve come up with (thanks to Brandon for brainstorming the plugin API with me).
Behind the Scenes
The good news is that the API for storing files in GridFS using Ruby is nearly identical to using Ruby’s File class. Unfortunately, that is also the bad news, in my opinion, as I find Ruby’s File open, read and close a bit awkward. Here are a few examples pulled almost directly from Grip:
# write foo.jpg to grid fs file = File.read('foo.jpg') GridFS::GridStore.open(database, 'foo.jpg', 'w', :content_type => 'image/jpg') do |f| f.write(file) end # read foo.jpg from grid fs GridFS::GridStore.read(database, 'foo.jpg') # delete foo.jpg from grid fs GridFS::GridStore.unlink(database, 'foo.jpg')
Not horrible but not beautiful. There is a bunch of GridFS related code on Github. To highlight a few interesting ones:
That is all for now. Enjoy the GridFS goodness and the future hope of an awesome MongoMapper plugin interface.