Getting started with CouchDB: A simple address book application
I've recently installed CouchDB but, still being pretty new to this whole document store thing, don't really know what they can do or how to make CouchDB do it.
The best way to learn, of course, is to do. I've decided that I'll implement a simple address-book implementation.
Investigation and technology choice
Since CouchDB talks JSON I figure that I'll write the address book in Javascript and HTML, and because CouchDB includes a web server I'll serve the application from the same place I store the data. I'll call the file that contains that addressbook application addressbook.html.
Taking a peek at the CouchDB configuration in /usr/local/etc/couchdb/couch.ini I see that the document root for the web server can be found at /usr/local/share/couchdb/www - that's where the addressbook.html file will go.
I'll need a database to store people's contact details in. There's a pretty nice interface to do this at /_utils/ which is accessible using a web browser by pointing it at the CouchDB server's IP address and port.
CouchDB comes with a Javascript wrapper which can be found at /_utils/script/couch.js but it only talks to a local server and I'm accessing the page across the internet so I'll steal some code from it and change it to work for my setup.
Implementation
First off, create the database. Jump into the interface at /_utils/ and create a database called "addressbook". That's where we'll store our data.
The user interface is going to be a webpage using Javascript which makes things pretty simple. I'll whip up a really simple page to start with.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- The javascript will live in addressbook.js -->
<script src="http://aaa.bbb.ccc.ddd:5984/_utils/addressbook.js"></script>
<title>Address Book</title>
</head>
<body>
<h1>Address Book</h1>
<div id="addressbook">
<p id="loading">Loading... please wait...</p>
</div>
</body>
</html>
Since I've been spoiled by ActiveRecord I want to be able to say something like var people = Person.find("all"); in my code and have it return all Person records. I also want to be able to say Person.find("123456-1234-1234-123456"); to find an individual person.
Person = {
// Push the implementation details of the database into a
// different object to keep Person clean.
//
database: AddressBook,
find: function(id) {
if(id == "all") {
return this.database.allCards();
} else {
return this.database.openCard(id);
}
}
}
I've chosen to implement an AddressBook object that will abstract the details of database connection from the Person object. It will provide two methods, allCards and openCard(id). These methods talk to the CouchDB server and handle any and all data marshalling or other tricky bits and pieces.
AddressBook = {
// Change this to point to your own CouchDB instance.
uri: "http://craig-01.vm.xeriom.net:5984/addressbook/",
_request: function(method, uri) {
var req = new XMLHttpRequest();
req.open(method, uri, false);
req.send();
return req;
},
// Fetch all address book cards.
allCards: function() {
var req = this._request("GET", this.uri + "_all_docs");
var result = JSON.parse(req.responseText);
if (req.status != 200)
throw result;
var allDocs = [];
for(var offset in result.rows) {
var id = result.rows[offset]["id"];
var doc = this.openCard(id);
allDocs[allDocs.length] = doc;
}
return allDocs;
},
// Fetch an individual address book card.
openCard: function(id) {
var req = this._request("GET", this.uri + id);
if (req.status == 404)
return null;
var result = JSON.parse(req.responseText);
if (req.status != 200)
throw result;
return result;
}
}
I push responsibility for parsing JSON off to another library. Luckily, Yahoo provide a rather nice JSON library that does just what I'm looking for - I don't have to implement it, but I do need to pull it into the webpage, and make it appear in the global namespace.
<!-- Add this to the head of addressbook.html -->
<script src="http://yui.yahooapis.com/2.5.2/build/yahoo/yahoo-min.js"></script>
<script src="http://yui.yahooapis.com/2.5.2/build/json/json-min.js"></script>
// Make YUI JSON available in the global namespace.
// Add this to addressbook.js
JSON = YAHOO.lang.JSON;
The last piece of Javascript I need to show the address book is something to load all people from the address book and add them to the page. This uses window.onload hook which is bad, but for this little application is a quick and easy to kick off some code.
// This is horrible, I know, but it's just a simple example.
window.onload = function() {
var addressbook = document.getElementById("addressbook");
var personList = document.createElement("ul");
for(var offset in people) {
var person = people[offset];
var personNode = document.createElement("li");
var name = document.createTextNode(person.name);
personNode.appendChild(name);
personList.appendChild(personNode);
}
addressbook.removeChild(document.getElementById("loading"));
addressbook.appendChild(personList);
}
That's it; the application is ready to go. Upload the addressbook.html and addressbook.js file to the document root of the CouchDB server, fire up your browser and navigate to http://aaa.bbb.ccc.ddd:5984/_utils/addressbook.html where aaa.bbb.ccc.ddd is the IP address of your CouchDB instance.
A blank page that says "Address Book" should greet you. Not very impressive, right? What went wrong? Actually, nothing went wrong. There's just no data in the database.
The interface that I pointed out before for browsing and creating databases can also be used to add documents to the database. Jump into it again, navigate to the addressbook database and add a document. When it asks you for an id, just leave the field blank: it'll create one automatically. Add a field to the document called name and click the little green checkbox beside the textbox, then double click on the value of the new field and set it to your own name in quotes eg "Craig Webster". Click the green arrow beside the textbox then click "save document", jump back to the address book and hit refresh. The new record should now show up.
Moving forward
I've shown how to retrieve data from CouchDB using Javascript, but currently the data still has to be input using the CouchDB interface. Watch this space for an upcoming article on manipulating the database using Javascript so we cna add cards to the addressbook.
Did this article help?
If this article helped you, I appreciate beer if you meet me, or recommendations at Working With Rails.
Firewall a pristine Ubuntu 8.04 box
Follow these simple instructions to block all traffic but SSH to your box. Once you have these rules running you can punch more holes as required.
sudo apt-get install iptables
sudo iptables -A INPUT -i lo -j ACCEPT
sudo iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -p tcp --dport ssh -j ACCEPT
sudo iptables -A INPUT -j DROP
sudo sh -c "iptables-save -c > /etc/iptables.rules"
If you'd like to save your current rules when you stop - or load the rules when you start the box, change your /etc/network/interfaces file so that it contains pre-up and post-down hooks to load / save the rules.
pre-up iptables-restore < /etc/iptables.rules
post-down iptables-save -c > /etc/iptables.rules
Related articles
Getting started with Rails 2.0
Rails has changed quite a lot since Agile Web Development with Ruby on Rails (2nd Ed) was released. A number of new best practice techniques are now used in favour of those described in the book.
To demonstrate these techniques it is necessary to have a new Rails application to build upon. In this article I'll cover the basics needed to setup and run a Rails 2 project on your desktop or laptop. Future articles can then build on this base.
In this article
- Installing Rails 2.0
- Starting your Rails 2.0 project
- The importance of version control
- Working with the database: Models
- Creating dynamic pages: Views
- Hooking up the view and the model: Controllers
- What next?
Installing Rails 2.0
Rails 2 now uses SQLite as it's development and test database so you needn't worry about setting up MySQL on the development machine. This makes installing Rails and starting a new project a lot easier: we only have to get Ruby and the Rails code onto our machines. To simplify this even further use MacPorts. If you don't have that installed, go install it now. Remember to install XcodeTools - you can get it from your OS X install media if you didn't install it the first time around.
To install Ruby with MacPorts open Terminal.app (it's in Applications / Utilities) and run sudo port install rb-rubygems. Technically this command will install RubyGems, but since Ruby is a dependency that'll get installed too. Once RubyGems has installed (it might take a while) use that to install Rails by running sudo gem install -y rails.
That's pretty much it. You now have a working Rails install on your development machine.
Starting your Rails 2.0 project
First, to keep your home directory tidy, create an area to keep all your projects under. I call mine sandbox. In the terminal run the command mkdir ~/sandbox to create the sandbox.
Under the sandbox directory we want to create our project. To do this use the rails command, letting it know the name of your project - in this case I call my project QuickBite.
cd ~/sandbox/
rails QuickBite
You'll see a bit out output scroll past as Rails builds a basic project for you. Let's run that Rails app and see what we get.
cd QuickBite
ruby ./script/server
Open a web browser and type http://localhost:3000/ into the address bar.

It's not much, but our project now has a decent starting point. Lets save our progress in case anything bad happens.
The importance of version control
Version control does just what the name suggests: it allows you to control various version of your project. It's useful because it allows you to see when a change was made, what files the change affected, who made it, and it provides you the option of undoing changes that you don't like.
Git!
The version control system I use is Git. It does lots of cool things, but most of them won't be used until later articles. For just now we're only interested in being able to add changes to our projects so we can undo them if something bad happens.
You are of course free to use whichever system you're comfortable with, but the commands given in this article will only cover Git use.
Installing
Installing Git is simple if you use MacPorts. Simply run sudo port install git-core from the Terminal. Grab a cup of coffee, this can take a while.
Configuring Git
Since Git has only just been installed it doesn't know who we are. Let's tell it.
git config --global user.name "Your Full Name"
git config --global user.email "you@domain.com"
This is useful when working in teams as it lets you check who made a change to the code but it's a good idea to get it set up correctly from the get-go. By using --global we tell git that we want to use these values for all projects, not just this one - you only have to set your name and email address once.
Adding your Rails project to Git
Version control is great, but sometimes we don't want to version certain kinds of file. In a file called .gitignore in the top-level directory of your project add the following directives to ignore development and test databases, generated documentation, logs and temporary files that may be generated while running or developing a Rails project.
.DS_Store
db/*.sqlite3
doc/api
doc/app
log/*.log
tmp/**/*
Git is different from most version control systems in that it tracks content rather than files. We've told Git to ignore all content in tmp/ and log/ but we do want those directories to exist - Rails complains if they don't - so you'll need to create two .gitignore files, one in tmp/ and one in log/.
touch tmp/.gitignore
touch log/.gitignore
Now that Git in only paying attention to the files we're interested in we can add the project.
# Create the repository
git init
# Add the project to the next commit
git add .
# Commit the changes
git commit -m "Setup a new Rails application."
Normally we won't add . as it adds all uncommitted files under the current directory to the next commit. It's preferable to pick the files we want to commit (called staging in Git-speak) by using git add <filename> then using git commit -m "Commit Message" to commit just the staged files.
Once that's committed we can start building our application.
Working with the database: Models
In order to make a useful application we need to model the problem domain that the application operates in. Most - though not all - models interact with a database. Models can be found in app/models/, although there won't be any there yet.
The application I've created is called QuickBite. It's going to be an application for exchanging sandwich recipes. Sandwiches usually have a name - BLT, New York Deli, that sort of thing. We can tell Rails about Sandwiches by generating a model.
ruby ./script/generate model Sandwich name:string
If you look at the output of this command you'll notice that it's created a file in app/models/sandwich.rb. That's our sandwich model. The generator has also create some files called migrations. Migrations are commands that tell Rails how to manipulate your database - adding, deleting and renaming tables, columns and indexes. By running the migrations we ask Rails to tell the database what we know about sandwiches.
# Run any pending migrations
rake db:migrate
Now that Rails knows about sandwiches we should commit our changes to the source code repository in case something bad happens. The generator created some tests for us. I'm going to be a bad man and ignore those for just now - I'll cover testing at a later date.
# Look to see what's been changed
git status
# Stage the models, migrations, schema and tests.
git add app/models/ db/migrate/ db/schema.rb test/
# Commit the changes with a message
git commit -m "Added a model to represent sandwiches."
Creating dynamic pages: Views
Rails knows about sandwiches, but that doesn't help us get information into the database or show the people visiting our application what we've added to the database. We want to create a page that allows us to enter sandwich details and to let people see those details.
Pages are made up of several views - in our case we're just going to use one per page to keep things simple. Views live in subfolders of app/views/. If you take a look you'll see that there's already one subfolder there: layouts. Ignore it for now - we'll play with layouts soon, but they're not needed to get a basic application up and running.
Create a file called app/views/sandwiches/new.html.erb containing the following simple form which will allow us to create sandwich records.
<form action="/sandwiches/create">
Name: <input type="text" name="sandwich[name]" />
<input type="submit" value="Save" />
</form>
Now that we have a way of creating records we should allow people to see them. Create a file called app/views/sandwiches/show.html.erb containing the following code.
<p>This sandwich is called <%=h @sandwich.name %>.</p>
There are three important things to notice about the view we've just created.
- ERb output blocks (
<%= ... %>) are used where something - such as the sandwich name - should appear in the output HTML. - The helper method h is used to make sure that the output is properly sanitised HTML ie it doesn't include any nasty HTML tags that could mess up our page.
- The variable we're using starts with an @ symbol. It's not important to understand why at this stage, but it's important to take note of.
Let's try to create a sandwich. Fire up a browser and visit http://localhost:3000/sandwiches/new.

Oh no, an error! Rails doesn't know what we mean by asking for /sandwiches/new. We should tell Rails what to do when we ask for our new sandwich form, but first we should commit our views in case we screw anything up.
# Check what's changed
git status
# Stage the views for the next commit
git add app/views/sandwiches
# Commit the changes
git commit -m "Added create and show views for sandwiches."
Hooking up the view and the model: Controllers
Controllers tell Rails what to do when the view wants to talk to the model - for example when a view sends data as the result of someone hitting the submit button of a form, or when a browser requests a view. Controllers live in app/controllers/. There will already be one there, the application controller, which we will use as a base for our other controllers.
Create a new file called app/controllers/sandwiches_controller.rb
class SandwichesController < ApplicationController
def new
end
def create
@sandwich = Sandwich.create(params[:sandwich])
redirect_to :action => 'show', :id => @sandwich
end
def show
# Notice that this variable starts with an @ to match the view.
@sandwich = Sandwich.find(params[:id])
end
end
Now that we have told Rails what to do when we submit data, fire up a browser and visit the new sandwich form again. This time when you should see your form, and when you hit save you will be shown the sandwich record you've just created as a webpage.

Success! Our application allows us to create sandwiches and share them with visitors. One last time (for this article), save your progress.
# Look to see what's been changed
git status
# Stage the sandwiches controller
git add app/controllers/sandwiches_controller.rb
# Commit the changes with a message
git commit -m "Added a controller for sandwiches."
What next?
You've seen how to install Rails 2 and create a basic project that allows you to create sandwich records and show them to people.
In the next article we'll flesh out some missing functionality by providing a sandwich index so visitors can find sandwiches and a way of editing and deleting sandwiches, and we'll start using layouts and partials to DRY up views and make them look good. Stay tuned!
If you've found this article useful I'd appreciate recommendations at Working With Rails.
You may also be interested in attending my Rails tutorial at Scotland on Rails Charity Day in Edinburgh, Scotland on April 3rd 2008.
Related articles
I'm talking at Scotland on Rails
For three days (03 April to 05 April 2008) Scotland on Rails will host a ton of cool speakers covering a massive array of interesting subjects.
I'm talking at the charity tutorial day introducing Rails for those that are not already familiar with it. I'll be covering some best-practice techniques in the talk so even if you already know Rails, come join in, spread the love.
There's still time to register though places are limited so be quick!


