
These days we need our rails apps to do double duty- serving first as the user experience when someone comes to the site (rendering out HTML) and second serving as a platform for mobile applications or partner application. The current solution to serving as a platform is to render out JSON. This is a great solution, making use of our existing controller and model infrastructure. However Rails is a framework built on Model View and Controller. Where is the View when we’re serving out JSON? I think that using a JSON view fits the rails paradigm and makes development easier. I’m using RABL, I’d like to walk you through what using RABL for your JSON view looks like.
First, though, let’s look at how rails handles the JSON layer before any of this. Hopefully I can help illustrate why I believe this is not a scalable solution. ActiveModel includes a method called as_json. This takes your model and serializes it down into JSON. Neat! And it works pretty well. What happens though when you want to include nested attributes? Well there are two option, use the :include keyword in your controller or override the as_json method. Something like:
def as_json(options={})
super(:only => [:username, :favorite_coffee], :include =>[:recipes])
end
This includes online the username and includes the nested recipes that belong to each User. This is great! By now your front end guy (or hey, maybe that guy is you wearing a different hat), needs the favorite_coffee attribute to come back as favoriteCoffee. Well, ok it’s one change away in the as_json. And, shoot, now you need to include different attributes based on different permissions. What’s the solution then? Pass what level the current user is down to the model? That doesn’t make a ton of sense to me, authentication is usually handled at the Controller level.
And, here we are at RABL. RABL is a view layer you’ve been dreaming about for Javascript. Now I’d like to walk through building a sample app.
Quickly!
rails new coffeeHouseApp
rails generate scaffold Patron name:string favorite_coffee:string credits:integer grouchy:boolean
rails generate scaffold Laptop name:string operating_system:string patron_id:integer
rake db:migrate
And then drop in the relationships
class Laptop < ActiveRecord::Base
belongs_to :patron
end
class Patron < ActiveRecord::Base
has_many :laptops
end
Ok, great! We have a functioning app. Now the real RABL’ing begins. First, we need to make sure rabl is part of our Gemfile. You know how that goes, drop this line into your Gemfile:
gem 'rabl'
and then tell bundler to go get that dependency
bundle install
Now we want our patron record to render out as a nice JSON representation. We first need to update the controller:
# GET /patrons/1
# GET /patrons/1.xml
def show
@patron = Patron.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json
end
end
Now we need to provide that JSON template. Create a new file under app/views/patrons/show.json.rabl Inside that file let’s put the following:
object @patron
attributes :name, :favorite_coffee
child :laptops do
attributes :name
end
This exposes an object called patron, and only the name and favorite coffee attributes. It also exposes the nested laptops, but only their name. This is great, we’re keeping the grouchy attribute secret on the Patron. After all, we don’t want our third party partners taking advantage of our grouchy patrons. Also under laptop we’re only exposing the name. Good call again, for security. The resulting JSON looks like this:
{
"patron": {
"name": "Nick Rowe",
"laptops": [
{
"laptop": {
"name": "Lappy"
}
}
],
"favorite_coffee": null
}
}
So now here’s where it gets cool. One of the business guys gets wind that we’re calling them patrons. “Oh no, he insists, that’s far too formal. We call them Guests. And, we do want to expose the grouchy attribute but only on days of the month divisible by 7” A bit, weird but not problem. Our template now looks like this:
object @patron => :guest
attributes :name, :favorite_coffee => :favoriteCoffee
if (Date.today.day % 7 == 0)
attributes :grouchy
end
child :laptops do
attributes :name
end
Nice! Well that’s a taste of RABL. You can learn a ton more by checking out the RABL github page. You can also learn more about why the original author thought RABL was a good idea by checking out his blog.
What do you think about RABL?