CouchDB on Rails (part 6 of ?)
- An introduction to CouchDB
- Installing CouchDB
- Experimenting with CouchDB's web interface
- Integrating with Rails using ActiveCouch
- Integrating with Rails using RelaxDB
- Getting to scaffolding using RelaxDB
- Installing CouchDB from Subversion source code
- Trying out couchrest and topfunky’s basic_model
Okay, after my brief disappointment earlier, i've found a way that seems to work, at least for the time being. I have taken the RelaxDB lines out of environment.rb and put them into the application controller instead.
# app/controllers/application.rb class ApplicationController < ActionController::Base require File.join(File.dirname(__FILE__), '../../vendor/plugins/relaxdb/lib/relaxdb') RelaxDB.configure(:host => 'localhost', :port => 5984) RelaxDB.use_db('cd_collection') end
Oh, i should say, i'm going to add the RESTful resources command into config/routes.rb:
map.resources :cds
I have also added some of the other properties into the model:
class Cd < RelaxDB::Document property :title property :artist property :publisher property :year_of_release end
It's a shame i have to do this. I'd like to see a wrapper for CouchDB which doesn't try to force a schema upon the database. That is one of CouchDB's biggest strengths – that documents can contain any fields you wish.
Index of all CDs
I know my boss will probably read this, so i'll do the right thing and start with a spec!
# spec/controllers/cds_controller_spec.rb describe CdsController do describe "index" do it "should look up all CDs in the database" do Cd.should_receive(:all).and_return([:some_cds]) get :index assigns[:cds].should == [:some_cds] end end end
And the code to make this pass is simply going to be:
# app/controllers/cds_controller.rb class CdsController < ApplicationController def index @cds = Cd.all end end
The spec passes. Let's write the view! Because RelaxDB wraps up the database so nicely for us, there is nothing unusual here at all.
<!-- app/views/cds/index.html.erb --> <h1>My extensive CD collection</h1> <table> <tr> <th>Title</th> <th>Artist</th> <th>Publisher</th> <th>Year of release</th> </tr> <% @cds.each do |cd| -%> <tr> <td><%= h(cd.title) %></td> <td><%= h(cd.artist) %></td> <td><%= h(cd.publisher) %></td> <td><%= cd.year_of_release.to_s %></td> </tr> <% end -%> </table>
Now we are definitely getting somewhere! :) But the CDs appear in the order they were created. To order them by artist then title, we can do this:
@cds = Cd.all.sorted_by(:artist, :title)
You know what RelaxDB is going to do now?
[info] [<0.2122.0>] 127.0.0.1 - - "GET /cd_collection/_view/Cd/all_sorted_by_artist_and_title" 200
Yep, it dynamically creates the views it needs. Clever, hey?! And here's the output:
Differences between ActiveRecord and RelaxDB
I'm not going to go through every line of code, but here are the main differences from ActiveRecord:
To find all CDs (as i already demonstrated):
# @cds = Cd.find(:all, :order => "artist, title") @cds = Cd.all.sorted_by(:artist, :title)
To find a CD from the parameters:
# @cd = Cd.find(params[:id]) @cd = RelaxDB.load(params[:id])
Updating attributes – there is no method 'update_attributes'. There is 'set_attributes' but it doesn't actually save the document – you have to do that yourself.
# @cd.update_attributes(params[:cd]) @cd.set_attributes(params[:cd]) @cd.save
Destroy requires an exclamation mark.
# @cd.destroy @cd.destroy!
Validations are rubbish. I managed to get it sort of working like this:
property :title, :validator => lambda {|t| t != ""}, :validation_msg => "cannot be blank" property :year_of_release, :validator => lambda {|p| p.to_i > 0}, :validation_msg => "must be a number"
And then in the view you have to do something like this:
<% @cd.errors.each_pair do |field, message| -%> <p><%= field.to_s.humanize %> <%= message %></p> <% end -%>
… it's very flaky though. Sometimes it lets it through even when the validation blatantly fails. Still, it's a known limitation.
My verdict on RelaxDB
I like it. I am glad that i had to change very little in the views to get it to work, and relatively few things in the controller. Apart from the validation and error messages, it's a good little plugin if you want to get going quickly on CouchDB. I'd like to see it allow dynamic fields on documents … that would be a good improvement.
I may work a bit more with RelaxDB … it would be good to find out how to link two models. Watch this space! :)
Part 7: Installing CouchDB from Subversion source code
Related posts (automatically calculated)

