CouchDB on Rails (part 5 of ?)

  1. An introduction to CouchDB
  2. Installing CouchDB
  3. Experimenting with CouchDB's web interface
  4. Integrating with Rails using ActiveCouch
  5. Integrating with Rails using RelaxDB
  6. Getting to scaffolding using RelaxDB
  7. Installing CouchDB from Subversion source code
  8. Trying out couchrest and topfunky’s basic_model

So today i'm going to try using the RelaxDB plugin. I am fortunate in that there is a tutorial already written, which might make it easier. However, the tutorial is for Merb, so it might not work at all on Rails. We'll see.

Start a new Rails project

I have deleted my previous project and i'm starting again. The initial steps are the same as last time to create the project, create a Git repository, and bring in RSpec.

$ rails cd_collection
$ cd cd_collection
$ git init
$ git submodule add git://github.com/dchelimsky/rspec.git vendor/plugins/rspec
$ git submodule add git://github.com/dchelimsky/rspec-rails.git vendor/plugins/rspec-rails
$ ./script/generate rspec

I'm slightly confused as to whether you're supposed to install RelaxDB as a gem, or whether it is okay just to include it as a plugin. For now i'm going to try as a plugin.

$ git submodule add git://github.com/paulcarey/relaxdb.git vendor/plugins/relaxdb

Spec tests

Like all good projects, RelaxDB has some RSpec tests, but before i can run them i need a few more gems such as extlib, json, uuid. Just use 'gem install' as root to install them. The specs will not run until you meet all the requirements.

I also found that the specs require CouchDB to be running on http://localhost:5984. As before, i use the su impersonate command to get it running.

$ sudo -i -u couchdb couchdb

And now for the moment of truth …

$ rake spec
..................................................................................................................
Finished in 6.620036 seconds
114 examples, 0 failures

Amazing! I'm feeling very hopeful about this! So let's jump straight in!

Configuration

A big win over ActiveCouch, RelaxDB has the option to set the database connection details. First i have to require the RelaxDB plugin … i'm doing this in config/environment.rb

require File.join(File.dirname(__FILE__), '../vendor/plugins/relaxdb/lib/relaxdb')

I suspect if i'd installed it as a gem i would have been able to just do this:

require 'relaxdb'

Never mind. It's fine. Now i can set my database connection details:

RelaxDB.configure(:host => 'localhost', :port => 5984)
RelaxDB.use_db 'cd_collection'

Create a model

The key thing today is to inherit from RelaxDB::Document. It seems i also have to set up the fields (in RelaxDB they are called properties). For now i'll just start with a title.

# app/models/cd.rb
class Cd < RelaxDB::Document
  property :title
end

Use script/console to ease us in gently

$ ./script/console
Loading development environment (Rails 2.1.0)
>> cd = Cd.new
=> #<Cd:23965060258520, _id: "deadea40-6256-012b-aeb2-001a9205e793">
>> cd.title = 'Made Of Bricks'
=> "Made Of Bricks"
>> cd.save
=> #<Cd:23965060258520, _id: "deadea40-6256-012b-aeb2-001a9205e793", _rev: "4255803143", title: "Made Of Bricks">

It is my lucky day!! Let's see if that actually did what i think it did. The CouchDB log file looks promising:

[info] [<0.1970.0>] 127.0.0.1 - - "GET /cd_collection" 200
[info] [<0.1972.0>] 127.0.0.1 - - "PUT /cd_collection/deadea40-6256-012b-aeb2-001a9205e793" 201

And yes, sure enough, here's my new document sitting happily in the database:

A new CouchDB document created via RelaxDB

I notice the 'class' field has been inserted with the value 'Cd'. This is clearly a special field that RelaxDB uses to map the document to a model in Rails. It's a much better idea than ActiveCouch which seemed to want a separate database per model.

What else can we do? Find our CDs again? In ActiveRecord you'd do Cd.find(:all) but in RelaxDB it's just Cd.all

>> Cd.all
=> [#<Cd:23965059931020, _id: "deadea40-6256-012b-aeb2-001a9205e793", _rev: "4255803143", title: "Made Of Bricks">]

I wonder if i can trick it into finding the other CDs in my database, if i add the 'class' field to them all …?

>> Cd.all
=> [#<Cd:23965059900720, _id: "1", _rev: "1785545430", title: "Unwritten">, #<Cd:23965059892540, _id: "2", _rev: "1917382848", title: "Screaming Serenades">, #<Cd:23965059874120, _id: "3", _rev: "548309184", title: "Harry Potter and the Order of the Phoenix">, #<Cd:23965059858260, _id: "4", _rev: "288823659", title: "N.B.">, #<Cd:23965059840120, _id: "5", _rev: "374227142", title: "Vampire Weekend">, #<Cd:23965059821740, _id: "deadea40-6256-012b-aeb2-001a9205e793", _rev: "4255803143", title: "Made Of Bricks">]

Sure enough, yes! It works! And look what else i've just seen:

RelaxDB made its own view

RelaxDB helpfully created the view that it needed to search for CDs. I am very impressed.

Searching by ID is slightly different from ActiveRecord. Instead of Cd.find(id) we need RelaxDB.load(id) …

>> RelaxDB.load(1)
=> #<Cd:24003693527840, _id: "1", _rev: "1785545430", title: "Unwritten", artist: "Natasha Bedingfield">

Oh, by the way, i added 'artist' as a property in the model. That works too! :)

Remember that most documents will be looked up using a UUID that RelaxDB will generate for us. That first CD just happened to be ID 1 because i gave it that ID the other day.

>> RelaxDB.load("deadea40-6256-012b-aeb2-001a9205e793")
=> #<Cd:24003693442460, _id: "deadea40-6256-012b-aeb2-001a9205e793", _rev: "4255803143", title: "Made Of Bricks">

There doesn't seem to be a 'find' method. I don't know how we would find the first CD, or search by title.

RelaxDB can delete documents using a 'destroy!' method:

>> cd = Cd.new(:title => "Delete me")
=> #<Cd:23749309141020, _id: "77d7a1f0-625b-012b-aeb4-001a9205e793", title: "Delete me">
>> cd.save
=> #<Cd:23749309141020, _id: "77d7a1f0-625b-012b-aeb4-001a9205e793", _rev: "1029394382", title: "Delete me">
>> RelaxDB.load("77d7a1f0-625b-012b-aeb4-001a9205e793")
=> #<Cd:23749309081880, _id: "77d7a1f0-625b-012b-aeb4-001a9205e793", _rev: "1029394382", title: "Delete me">
>> cd.destroy!
=> #<Cd:23749309141020, _id: "77d7a1f0-625b-012b-aeb4-001a9205e793", _rev: "1029394382", title: "Delete me">
>> RelaxDB.load("77d7a1f0-625b-012b-aeb4-001a9205e793")
RuntimeError: 404:Object Not Found
METHOD:GET
URI:/cd_collection/77d7a1f0-625b-012b-aeb4-001a9205e793
{"error":"not_found","reason":"deleted"}

Dead end

Unfortunately, i seem to have come to a dead end here. Although i think i have everything needed for some basic web app scaffolding, i keep getting the following error when i try to load a page in a web browser:

Rails error when trying to connect to CouchDB

You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.reverse

This happens even if i have a completely empty action in the controller.

The error seems to be coming from ActiveRecord, so i think something is still calling ActiveRecord when it shouldn't. Anyone got any ideas? Why would it even bother to load ActiveRecord when the model inherits from RelaxDB?

Anyway, i'm not finished with RelaxDB yet. I like what i've seen so far. I'll publish this progress and hope to get some feedback on the error. My next post will hopefully be a tutorial about creating the Rails scaffold.

Edit to add: The problem comes when i include relaxdb in the environment.rb. Is there a way to get around this?

Edit again to add: It does seem to work if i put the include statement into the application controller. I think i'm back on track. Stay tuned for the next installment!

Part 6: Getting to scaffolding using RelaxDB

Related posts (automatically calculated)

  1. CouchDB on Rails (part 6 of ?)
  2. CouchDB on Rails (part 4 of ?)
  3. CouchDB on Rails (part 8 of ?)
  4. CouchDB on Rails (part 2 of ?)
  5. CouchDB on Rails (part 3 of ?)

This entry was posted on Thursday, September 11th, 2008 at 19:50 and is filed under couchdb, ruby on rails. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

8 Responses to “CouchDB on Rails (part 5 of ?)”

  1. Ben Atkin UNITED STATES Windows XP Mozilla Firefox 3.0.1 Says:

    It's interesting to see how RelaxDB builds on CouchDB. Since CouchDB is so simple, there are many ways to use it, and it's nice to have a library like RelaxDB that provides an example of one way to use it. It looks like RelaxDB makes it easier for people who are used to thinking in terms of tables to begin using CouchDB.

    Nice article. I like how you show every step you take, because I can pick up on little unrelated bits of information (like the "-i" option that can be passed to sudo). It feels like I'm watching a screencast, except I can learn at my own pace and headphones aren't required.

  2. Chris Anderson UNITED KINGDOM Mac OS X Safari 525.20 Says:

    It's really helpful to see the contrast between these frameworks. I'm beginning to think about how best to layer an application-model style wrapper on top of CouchRest. It's good to see what's helpful and what gets in the way, or is missing from these other libraries. Keep up the good work, looking forward to what's next!

  3. Aimee UNITED KINGDOM Debian GNU/Linux Mozilla Firefox 2.0.0.16 Says:

    @Ben, thank you for your encouragement.

    @Chris, i think the most important and useful feature would be to make use of CouchDB's dynamic document structure. If you can make a library that doesn't try to apologise for CouchDB's lack of schema, that would be awesome! :) I think the ability to create its own views when it needs them is a very strong feature.

  4. Randy UNITED STATES Mac OS X Mozilla Firefox 3.0.1 Says:

    If you are having problems running the spec, you might need to update your gems.

    This is the error I was getting:

    undefined method `generate' for "0322b6d0-6270-012b-24ea-0017f2d556c5":String

  5. Aimee UNITED KINGDOM Debian GNU/Linux Mozilla Firefox 2.0.0.16 Says:

    Hi Randy, the specs are working just fine for me with the RelaxDB. Is your CouchDB server running?

  6. Bruno BRAZIL Ubuntu Linux Mozilla Firefox 3.0.3 Says:

    Hi Aimee. First of all congratulations on your blog. I'm learning a lot.
    Now I need some help with running the rspec in my project.
    I'm getting the error:
    rake aborted!
    #42000Unknown database 'sysx_development'
    when i run "rake rspec". This is the database that is in my database.yml file and is setted to mysql. I tried to configure the file like this:
    development:
    adapter: couchdb
    database: sysx_development
    host: 127.0.0.1
    port: 5984
    After that, executing rspec asks for a gem called activerecord-couchdb-adapter. But it doesn't exist. Am I going throw the wrong way?

  7. Aimee UNITED KINGDOM Ubuntu Linux Mozilla Firefox 3.0.3 Says:

    Hi Bruno,

    I don't think you can use database.yml together with CouchDB. There is no couchdb adapter that i know of.

    If you're using RelaxDB you could try putting the details into your config/environment.rb:

    RelaxDB.configure(:host => 'localhost', :port => 5984)
    RelaxDB.use_db 'sysx_development'

    I can't remember whether i maybe had to create an empty MySQL database just so that the database.yml didn't cry.

  8. Bruno BRAZIL Ubuntu Linux Mozilla Firefox 3.0.3 Says:

    Hi Aimee,
    I configured the app like you sad. But when rails initialize it keeps calling the database.yml. I tried to turn off in enviroment.rb:
    config.frameworks -= [ :active_record, :active_resource, :action_mailer ]
    There's a bug in rails that it doens't work very well. I think I'm missing something here. Do you have your source code anywhere so I can look at it?
    thanks

Leave a Reply