I wrote recently about getting started with Merb. Yesterday, after having refer to my own post to remember how it all worked, I started on a new Merb app as part of the Great Grabb.it Rewrite of 2008. I very quickly ran into another area of Merb that's a bit thin on documentation: Controllers. After some googling, some fiddling, and some brainstorming in the #merb irc channel I managed to figure out enough of the basics to get things up and running.
Right now, Merb's sweet spot seems to be as an API server, which is exactly how we're planning on using it. This usage means that while there might be a little bit of model integration for access control, most of the job is in routing URLs and data formatting. That means we'll be spending most of our effort in config/router.rb and in our controllers. Specifically, we'll need to know a lot about how Merb provides responses in various formats depending on the request url, i.e. it's equivalent to Rails' respond_to method. Let's start by laying out our requirements and then I'll show you how I translated them into Merbish.
For this app, I needed to take URLs within a namespace and route them to a single controller setting various params based on the rest of the request path. In other words, I wanted to provide URLs like:
So, the first thing I needed was a series of routes that would recognize all URLS starting with /music and then grab the path after the first slash into an :artist param and the path after the second slash into a :title param. Finally, it would need to look for a format after the dot and pass that through as well if available.
It turns out the best way to do this in Merb is with nested routes, thusly (inside of the Merb::Router.prepare block in config/router.rb):
r.match('/music') do |music|
music.match("/:artist.:format").to(:controller => 'music', :action => 'artist')
music.match("/:artist/:title.:format").to(:controller => 'music', :action => 'track')
This is pretty self explanatory if you're familiar with Rails routes, though it is probably worth noting that an early version of this I tried which eschewed the nesting in favor of including the /music part of the path in each route separately seemed to have problems detecting the format correctly (though it is more than likely the cause was driver error on my part rather than anything that Merb might do differently in that situation). There's pretty thorough documentation on Merb routing if you need more specific help and that's definitely not the case for the Controller APIs, so let's tackle those right away.
Now, how do we consume those URLs in our application? We need a controller, thusly:
class Music < Application
display Track.new params[:artist], params[:title]
display Artist.new params[:artist]
There's two main things going on here that distinguish Merb's controllers from Rails': the 'provides' class method and the 'display' method we're calling in each action. These two methods work together to let us return our data in the right format on every request. And, while they might look confusingly different from the familiar Rails respond_to block at first, they turn out to make things much cleaner, eliminating the need to redeclare common formats over and over in each controller method.
While this should be enough to get you up and running writing Merb controllers, there are a few other details worth noting. First of all, if you want to provide alternative formats besides, js, html, xml, and the usual suspects (like we do here with jspf), you'll need to register a mime-type. We configured that by adding a single line to config/init.rb:
Merb.add_mime_type(:jspf, :to_jspf, %w[application/jspf+json])
There's lots of other additional information about the request available to your controller actions as well, such as content_type. Secondly there's other options besides display for returning content from your action. Calling "render" will attempt to automatically detect a template with the right format in the appropriate views directory. And you can always just render a raw string. Again, more details are available here.
There's the beginnings of a great open source book being written by some folks on GitHub: Life On The Edge With Merb, DataMapper & RSpec.They've done a pretty solid job covering the basics of app initialization, modeling with the DataMapper ORM, and testing with RSpec so far, but their section on Controllers is blank so far. If someone wants to pick up the thin thread I've laid down here and run with it, that would be a great place for more documentation to accumulate.