Attachments with CouchDB and Rails

In response to my recent CouchDB on Rails tutorial, somebody asked the following question:

Let's imagine, that you want to store a picture of grandma along with her contact-info – how exactly would I do that?

Well, Stf, here's the answer, with a picture of my actual grandma to illustrate!

Attachments with CouchDB and Rails

The first thing you need to understand, CouchDB stores attachments in a special field, called _attachments. It can store multiple attachments inside that field, as an array. This means that you can upload a picture, and later come back and upload another picture, and they will be stored alongside each other.

I have implemented the attachments in such a way that it will display images inline, scaled down to 200px width. It's kind of a crude thumbnail. You can click on the picture to open it full size.

CouchRest and BasicModel make this pretty easy for us. We check whether the contact has any attachments, loop through the attachments, decide to display an image if it is png or jpg, otherwise link to the file name.

<% if @contact._attachments -%>
  <h2>Attachments</h2>
  <% @contact._attachments.each do |attachment_name, attachment_attributes| -%>
    <% if %w(image/jpeg image/png).include?(attachment_attributes['content_type']) -%>
      <% link_content = image_tag(attachment_contact_path(:id => @contact,
        :filename => attachment_name), :width => '200') -%>
    <% else -%>
      <% link_content = attachment_name -%>
    <% end -%>
    <%= link_to(link_content, attachment_contact_path(:id => @contact,
      :filename => attachment_name), :popup => true) %>
  <% end -%>
<% end -%>

You may notice the attachment_contact_path – this is done with a little tweak in config/routes.rb:

map.resources :contacts, :member => {:attachment => :get}

Now we can add a controller action attachment which finds the attachment and renders it in full. This will involve displaying an image at full size, or launching a file in the appropriate application if it cannot be rendered inline.

def attachment
  @contact = Contact.find(database_name, params[:id])
  metadata = @contact._attachments[params[:filename]]
  data = Contact.db(database_name).fetch_attachment(@contact.id,
    params[:filename])
  send_data(data, {
    :filename    => params[:filename],
    :type        => metadata['content_type'],
    :disposition => "inline",
  })
end

Acknowledgements and thanks to topfunky for the peepcode-couchdb-code tutorial which gave me most of the information i needed to know in order to do this.

Posted: December 15th, 2008
Categories: couchdb, ruby on rails
Comments: View Comments.
  • Your blog is great! I like it; I want to make friends with you
  • The scenery is beautiful and calm,I want to live there
  • Bookmarked! I'm a code newbe so all such step-by-step guides come handy ...
  • Its really cool, I came to know this really worth visiting, just bookmarked your site.

    http://gisnap.com/
    The place where fun never ends
  • gene123
    Hi Aimee,
    I am new in ruby and couchDB. What is the code if I need to open a folder of images and add each of them in couchDB? Thank you for help.
  • One of the options we have, is to use something like CouchDB to be able to create an uber-flexible database that can evolve over time, and be very scalable. because our new product will be a SaaS one. Its pretty clear to see why CouchDB fits the bill.
  • I cant pass this:
    <% link_content = attachment_name -%>
    <% end -%>
  • What a useful post here. Very informative for me..TQ friends...

    Cheers,
    Buat Duit Dengan Blog
  • hi Aimee,

    ready! www.madrugaonrails.com.br

    happy holidays.

    Leonardo
  • stf
    Holiday Season and I got my presents even before christmas eve!! Thx for the missing piece&happy holidays to you from germany.
  • Hey Leonardo! That's wonderful, how exciting!

    Let me know when it's done and i'll link to it.
  • Hi Aimee,

    my name is Leonardo, I am translating your tutorial couchdb fot pt_br(portuguese Brazil).

    Congratulations on your blog, I added a link on my blog.
blog comments powered by Disqus