Tuesday, July 14, 2009

Over 1,000 Documents

‹prev | My Chain | next›

With the couch_design_docs gem, I am able to easily drop and recreate my development (and ultimately my production) CouchDB database. This all began because I wanted to load all of my meals and recipes in to my development database. So let's do it!

First up, I drop my old database:



Then recreate it:



Now I reload all of my design documents with couch_design_docs and the rake task that I created yesterday:
require 'couch_design_docs'
task :load_design_docs do
CouchDesignDocs.upload_dir("http://localhost:5984/eee", "couch/_design")
end
After running rake load_design_docs, I do a quick double check to find that yes, my design documents are now in the database:



Now that I think about it, I will likely be dropping and recreating my development CouchDB quite a bit now that the couch_design_docs gem makes it easy to reload my design docs. Rather than going through that manual process each time, I ought to automate this with rake (and do a little namespace organization while I am at it):
namespace :couchdb do

desc "Drop and re-create the CouchDB database, loading the design documents after creation"
task :reset => [:drop, :create, :load_design_docs]

desc "Create a new version of the CouchDB database"
task :create do
RestClient.put DB, { }
end

desc "Delete the current the CouchDB database"
task :drop do
RestClient.delete DB
end

require 'couch_design_docs'

desc "Load (replacing any existing) all design documents"
task :load_design_docs do
CouchDesignDocs.upload_dir(DB, "couch/_design")
end
end
It has been a while since I uploaded documents from my legacy Rails application into my new CouchDB store. The instructions for uploading my recipes include re-opening the Recipe class to add methods for CouchDB JSON generation:
class Recipe < ActiveRecord::Base

def _id; date.to_s + '-' + self.label end

def tag_names; tags.map(&:name) end

def _attachments
if self.image && self.image.filename
{
self.image.filename =>
{
:data => Base64.encode64(File.open(self.image.full_filename).read).gsub(/\n/, ''),
:content_type => "image/jpeg"
}
}
end
end

def couch_json
def self.type; "Recipe" end

self.to_json( :methods => [:tag_names, :_id, :_attachments],
:include => {
:preparations =>
{
:include =>
{
:ingredient => { :except => :id }
},
:except => [:ingredient_id, :recipe_id, :id]
},
:tools => { :except => [:id, :label] } },
:except => [:id, :label]).sub(/\{/, '{"type":"Recipe",')
end
end
I then run through each recipe in my legacy rails database, using the couch_json method to upload these documents to CouchDB:
>> ActiveSupport.use_standard_json_time_format=true
>> require 'restclient'
>> Recipe #load the current recipe class so that I re-open, not define
>> class Recipe < ActiveRecord::Base ... # the rest of the re-opened class from above
>> Recipe.all.each {|r| RestClient.put "http://localhost:5984/eee/#{r._id}", r.couch_json, :content_type => 'application/json'}
Similarly, the instructions for uploading my meals also have me re-open the Meal class to add methods for CouchDB JSON:
class Meal < ActiveRecord::Base
# IDs - date suffices for a meal (we never do more than one meal per day)
def _id; date.to_s end

# JSON for the CouchDB Document
def couch_json
self.to_json(:methods => [:_id, :menu, :type, :_attachments], :except => [:id, :image_old])
end

# For uploading meal images
def _attachments
if self.image && self.image.filename
{
self.image.filename =>
{
:data => Base64.encode64(File.open(self.image.full_filename).read).gsub(/\n/, ''),
:content_type => "image/jpeg"
}
}
end
end

# For the menu
def menu; menu_items.map(&:name) end

# To distinguish between meals, recipes, etc.
def type; self.class.to_s end
end
And, in Irb:
>> Meal.all.each{|m| RestClient.put "http://localhost:5984/eee/#{m._id}", m.couch_json, :content_type => 'application/json'}
With data in the application, it is time to fire up Sinatra. Initially, I get an error about missing the "kids" document in CouchDB (used to lookup nicknames that we use for the kids). After creating an empty kids document, I am able to navigate to http://localhost:4567 to see:



Yay! Over 1,000 documents (recipes and meals) are now loaded in my app and it seems to be working. I will do some smoke testing tomorrow to make sure that all is well. Then I need to figure out how to handle seed data like that "kids" document.

Update: The instructions were updated to reflect the need to format the dates in ISO 8601 format by setting ActiveSupport.use_standard_json_time_format=true.

No comments:

Post a Comment