Ruby Microframeworks: Camping and Cuba
We all know about Ruby on Rails and a great majority of us know about Sinatra. But, there’s a thriving ecosystem of small web frameworks for Ruby outside these two.
Don’t get me wrong; Sinatra is awesome! I’ve used it several times in the past, and, it has been great. However, it is important to learn about alternative approaches to the same problem.
Get a headstart by installing the frameworks we’ll be covering: “gem install cuba camping”
In this article, we’ll consider a couple of microframeworks in Ruby that take two substantially different approaches, compare them, and figure out their targeted use cases.
Cuba is the microframework that is probably my favorite for a number of reasons that we’ll see pretty quickly.
Let’s start off with the example application they provide:
Let’s say you save that to “hello_cuba.rb”
That’s pretty simple code, but, it accomplishes a lot. Cuba.define takes a block, in which we can use the “on” method, to which we pass “get”.
Then, inside another block, we can define the routes which respond to get requests.
However, to run this, you can’t just type in “ruby hello_cuba.rb”. Instead, Cuba applications run with Rack. Rack is basically an interface that gets Ruby talking to a webserver.
To get this working, you need a config.ru file (in the same location as the hello_cuba.rb file):
Now, to run this whole deal, type “rackup” into your Terminal (or, iTerm, Konsole, Powershell; we don’t judge here), and you should have a server running (probably at port 9292).
Head on over to http://localhost:9292/, and, you should be redirected to /hello (check the URL bar), and should have a nice “Hello, world!” message on your browswer.
You might think this whole rackup deal is pretty nonsensical – but, when you deploy an app, it makes life a ton easier.
It becomes interesting when you try to write tests for Cuba apps. Check it out:
Coming from Sinatra, I think that’s incredible! Cuba has built-in support for writing concise, clean code for tests. Tests are something that are partly my coding workflow (they should be part of yours, too!), so I think this very convinient. As you can see, we fire a request, follow the redirect, and check the response (of course, you probably wouldn’t do this type of thing in very large pages, but, it works here).
Let’s write some more URL matching code:
We added a post request which returns some pretty unhelpful JSON, and, added a couple of GET methods. The post routes work as expected; on post do, and, off you go.
The /echo/:string route is very simple – you can go to something like localhost:9292/echo/rubysource, and, it will print “rubysource”. The /print route does the exact same thing, except, with URL parameters. Check out the syntax – you actually have to determine what you’ll use from the params before the block gets on its way. I personally think this helps me, for others, they might just like the params hash better.
Cuba also packs in all sorts of security functions. All you have to do in order to get access to them is add “Cuba.use Rack::Protection” at the top of the application code. That prevents great majority of attacks from happening to you! It even comes with built-in support for templates! This is something I dearly miss in other small frameworks and I love Cuba for it. It makes life very easy (it is just a render call).
Cuba’s philosophy is to write the web app in a couple of files, with most of everything global (just like Sinatra).
I’ve used Cuba for a wide variety of things, such as a realtime, single page application to a small invoicing application. It has worked really well for me. However, performance bugs are difficult to track down and code seperation isn’t meant to be there.
On to the next microframework!
Camping follows a radically different philosophy than Sinatra and Cuba – it is an MVC framework. Instead of having everything all munged together, Camping’s philosophy says that it is far better to keep things seperated, but still, in one file.
Here’s a super tiny application in Camping:
You can save this as “hello_camping.rb”, and run it with the “camping hello_camping.rb” command (assuming you installed camping like you should have at the beginning of the article), which should start a server on port 3301. If you slide on over to port 3301 with a browser, you should see “Hello, world!” displayed, fair and square.
The code is a little bit more complicated than that of Cuba, but it isn’t too bad. We first tell Camping what our modules are going to come under, which leads to the Camping.goes :Hello line, then we define a module in which the controller classes will be defined.
We only have one controller in our example,
Index derives from
R '/', which means that it is called on the root route. Inside, we have a method that responds to the GET request and prints out the response.
Camping has something called Markaby baked right in – it is basically a DSL in Ruby, so that markup can be generated by calling Ruby methods. Check it out:
We’ve defined a new
Hello::Views module which has methods that correspond to view names. We can render these views from the controller, as we have done. So, this is the View-Controller portion of MVC ready to go!
Running this (again, “camping filename.rb”) and pointing your browser in the correct direction, you should get a nice couple of headers, along with the title set. The Markaby DSL is remarkably complete and very useful, but for larger projects I still prefer HAML, ERB or Liquid.
Routes in Camping are pretty simple (straight from the guide):
As you can see, the primary method of handling routes is via regular expressions. I’ve used this in the past with frameworks such as Django in Python, but I don’t find it as appealing for quick projects as the Sinatra/Cuba style routes. In the end, it is your choice and regular expressions can be far more powerful.
There is an alternative way to match routes (with a patterns in the controller class names), but I’ve found this system very buggy and more pain than it’s worth. If you want to use it, check out the docs.
Speaking of docs, Camping probably has the most excellent docs I’ve seen for any web framework other than Flask (which is Python-based). Even though they don’t go in insane depth, they are easy to read and get you strated very quickly, so I highly encourage you to check them out.
One of the coolest features of Camping are models. Here’s an example:
That’s not actually a complete web application (since we don’t have any controllers or views), but we can play around with in a console.
Before that though, let’s take a look at the code. We have classes in the People::Models module, underwhich we store both migrations and models. The models must come before the migrations. As for migrations, if you know how they work in Rails, you know how they work here. Basically, the database querying parts of Rails (ActiveRecord) are reused in Camping, so much of the interface is the same.
The migrations have version numbers specified by deriving from the “V” class, so, you can stack migrations one upon another by specifcing successive version numbers.
To play around with this, run
camping -C filename.rb in your terminal, which should get a console. Here’s what’s awesome – starting the console creates the database and runs the migrations!
As for using the console, if you’ve used the Rails console (which is the best thing since sliced bread), the interface will feel very similar. Except that in order to reference models, you must use “People::ModelName”, so, in our case “People::Models::Person”. Stuff like the following is interesting to try out:
Comparing Camping with Cuba, it has a completely different ideology in terms of separation of concerns. There are many times where one will work better than the other in some sets of applications. Most of the time, for small projects, it doesn’t really matter – pick what you’re comfortable with.
I really love Camping for its incredibly simple database interaction. This is harder with Cuba, since you have to use an external library, such as DataMapper. Also, the included benefit of having the excellent console is really amazing for catching bugs.
I usually use Camping for small projects that I might have used Rails for, but have little time and want development done quickly. I’ve used it several times for weekend projects and the like.
Wrapping it up
I hope you enjoyed the whirlwhind tour of two absolutely excellent microframeworks that have been designed with a ton of thought.
I’ve found these frameworks really useful, and I’ve tried to incorporate some of their ideas in other technologies that I work with (e.g. Rails).
Thanks, and, do leave feedback!