• If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • You already know Dokkio is an AI-powered assistant to organize & manage your digital files & messages. Very soon, Dokkio will support Outlook as well as One Drive. Check it out today!


Todos 06-Building with Merb

Page history last edited by Jim Tobin 14 years, 3 months ago

About Merb


Merb is a lightweight MVC-style Ruby framework for building web applications. Merb was originally conceived as an alternative to Ruby on Rails and improves on many aspects of Rails 2.0. As of December 23, 2008, the Merb project has begun to be merged with Rails, and a version with the best features of both will be released in late 2009 under the name Rails 3.0.


Merb is considerably more efficient (and thus faster) than Rails and is well-suited to serving a RESTful web service such as the one we will need for this tutorial.


Before You Get Started


You need to have Merb version 1.0.8 or newer installed. You can install it by running:


$ sudo gem install merb


If you already have it installed, you can update Merb by running


$ sudo gem update merb


This tutorial assumes that you will use Merb’s default database (sqlite3) and database ORM (DataMapper). Using the defaults eliminates the need for any configuration.

Sqlite3 comes preinstalled on OSX and many flavors of Unix. You can check whether it’s installed by typing sqlite3 on the command line, which will bring you to a sqlite3 prompt if it is installed.


Make sure you have installed the database driver that allows DataMapper to connect to sqlite3:


$ sudo gem install do_sqlite3


Create your Merb App


On the command line:


$ merb-gen app todos


This will set up a basic Merb app. You will need to keep your Merb server running in addition to your sc-server instance, so it’s best to open a new terminal window and change to the directory of the new Merb app you just created and run:


$ merb


If everything goes as planned, you should now be able to visit http://localhost:4000 to see your app running.


Setting Up the Database


If you are using Merb’s default database (sqlite3) and database ORM (DataMapper) there is no need for any configuration.

Merb’s generator has already set up a database.yml file which defaults to SQLite and a database named sample_development.db.


Creating a Merb Resource


Merb has a command, merb-gen resource, which creates a model, controller, and views all at once. We are building a web service for our SproutCore app so we don’t need views. Consequently, instead of using the merb-gen resource command, we’ll create a model and controller separately.


Create Your Model


Next, we need to create our model objects. Models are easy to create in DataMapper, very much like ActiveRecord in Rails (if you are familiar with that), except that you can describe your schema directly in your classes.


Create a new Task model using the generator command:


$ merb-gen model task


Inside of this model we need to define the properties we want to store for the task. (Note how this will be the same as we have in the client, but in a more complex app it often won’t be. Your client and server are isolated; that’s why we design it like this…)


In app/models/task.rb add:


class Task   

  include DataMapper::Resource    

    property  :id,            Serial   

    property  :description,   String,     :nullable => false   

    property  :is_done,       Boolean,    :default => false    

    property  :order,         Integer  



You now have your basic model setup. Let’s go ahead and get the DB configured. DataMapper has an auto-configuration system that will reset your database with the proper schema. Go back to the command line and run:


$ rake db:automigrate


Your database should now be configured. You can try it out. On the command line type:


$ merb -i


To get the interactive console in Merb.


NOTE: If you get an error that refers to “uninitialized constant Nokogiri,” you’ll need to update the “webrat” gem (sudo gem update webrat)


Now create a new task:


>> t = Task.new :description => "My Task", :order => 1  

=> #<Task description="My Task" is_done=false order=1 id=1>  

>> t.save  

=> true


Your task should now be added to the DB. Try to find it again:


>> Task.first :description => "My Task"  

=> #<Task description="My Task" is_done=false order=1 id=1> 


OK, your model is all set. Exit the shell so you can continue. Let’s get the controller written.


>> exit


Create Your Controller


Next, you need a tasks controller. This controller will actually respond to requests from your client.  Create a new Task model using the generator command:


$ merb-gen controller tasks


Open app/controllers/tasks.rb it will have the following content:


class Tasks < Application      


    index "Hello World"   




For this controller to receive requests, you will need to register it as a resource in the router. Open config/router.rb and add:




  resources :tasks 



Let’s see if that did the trick. Kill your Merb server, if you still have it running, and restart it. Then visit:




If everything went as planned, you should see “Hello World.”


Merb has the ability to format your responses in several different formats, but we only want to provide JSON in our response for this tutorial. Add this to the top of the controller, above the index action:


only_provides :json


If you want to support XML as well, you will need to tell the controller that we support both YAML, JSON and XML. Just replace only_provides with the following line. (You will have to add .json, .xml to your request urls)


provides :xml, :json, :yaml


Add an index action


OK, we have our basic app ready. Let’s get some actions working. The first thing we need to get going is the index action. This action should return JSON with the tasks inside. To get started, we need a helper method that can return the JSON data structure for a task. Add this to the bottom of the controller:



def json_for_task(task)     

  { :guid  => "/tasks/#{task.id}",

    :description => task.description,

    :order => task.order, 

    :isDone => task.is_done 




Finally, we need to update the index action to do the right thing. Replace the current index action with the following:


def index     

  tasks = Task.all.map { |task| json_for_task(task) }     

  ret = { :content => tasks, :self => '/tasks' }     

  display ret    



The code above constructs the JSON hash we would like to return (a hash with a content property that contains an array of records.)

Give it a try in the browser:




If it works, you will download a file containing this:


{"content":[{ "order":1,"description":"My Task", "guid":"\/tasks\/1", "isDone":false}], "self":"\/tasks"}


Let’s move onto the next action… returning a single task.


GET task


When we want to retrieve a single task, we need to get just the JSON for that task. This should be easy. Just add a new action to the controller:


def show     

  task_id = params[:id]     

  task = Task.get(task_id) rescue nil     

  raise NotFound if task.nil?     

  ret = { 

    :content => json_for_task(task), 

    :self => "/tasks/#{task_id}" 


  display ret   



Try it in the browser:




Creating a Task


We will accept JSON from the client. We are going to need a new helper method here. Add this method below the json_for_task:


def apply_json_to_task(task, json_hash)   

  task.description = json_hash['description'] unless json_hash['description'].nil?

  task.order = json_hash['order'] unless json_hash['order'].nil?

  task.is_done = json_hash['isDone'] unless json_hash['isDone'].nil? 



Now we can start creating some tasks. Add the following action just before the “protected” line:


def create      

  json = JSON.parse(request.raw_post) rescue nil?     

  json = json['content'] if json     

  raise NotFound if json.nil?          

  task = Task.new  

  apply_json_to_task(task, json)     



  # Return the location header with the new URL          

  url = headers['Location'] = "/tasks/#{task.id}"     

  ret = { :content => json_for_task(task), :self => url }            

  status = 201     

  display ret   



Updating a Task


Updating is nearly as easy. Just add this action:


def update      

  json = JSON.parse(request.raw_post) rescue nil?     

  json = json['content'] if json     

  raise BadRequest if !json          

  task_id = params[:id]     

  task = Task.get(task_id) rescue nil     

  raise NotFound if task.nil?     


  # Update task     

  apply_json_to_task(task, json)     



  # Return the updated JSON     

  ret = { 

    :content => json_for_task(task), 

    :self => "/tasks/#{task_id}" }     

  display ret   



Deleting a Task


This one is easiest. Just find the task and destroy it.


def destroy     

  task_id = params[:id]     

  task = Task.get(task_id) rescue nil          


  # if task was found destroy it.  If it was not found, do nothing     

  task.destroy unless task.nil?          


  "200 Destroyed"   



Setup Your Proxy


SproutCore applications can only communicate with the specific host/port they were loaded from. Since you are running the sc-server tool for development purposes, this is a problem because you load your app on http://localhost:4020 but your Merb app is running on http://localhost:4000. How do we fix this?


You’ll find that sc-server includes a handy proxy tool that solves this problem. We will want to proxy all requests for http://localhost:4020/tasks to http://localhost:4000/tasks. This is easy to setup. Just open the Buildfile file in your SproutCore project and add the following line to the bottom:


proxy '/tasks', :to => 'localhost:4000'


Now restart your sc-server. Remember you need to keep both the sc-server and your Merb app running. Now visit




You’re Done!


You should see a page from Merb. You’ve just created your first SproutCore-friendly web service. It’s worth noting now that you’ve not only done that, but you’ve just built a very nice API you can let others use to access your Todo’s service as well. Not bad for a few minutes of work.


This concludes the server-technology specific section of the tutorial. Please continue the tutorial with Step 7 below.


Continue to next step: Step 7: Hooking Up to the Backend »




  • The Building With Merb instructions were originally written by Charles Jolley for Merb version 0.9.3.
  • This version of the Building With Merb instructions (suitable for Merb 1.0.8) was written by Daniel Kehoe on 17 January 2009.
  • This was updated to work with SC 1.0 on April 17 2009 by Juan Pinzon 


Comments (0)

You don't have permission to comment on this page.