learns_to use the ternary operator to make concise views

1 March, 2006

Rails' templating system has lots of advantages. It's simple, lightweight, and intuitive. And since it's still just Ruby, you can refer to things exactly the same way as you would anywhere else in your application. The intuition you've built up working in your models and controllers and script/console (you do you use script/console constantly while you're developing, don't you? If not, you're missing out on about half the fun of Rails) about how to call up your user's name will still hold: it's still just @user.name.

The one downside I've found is that the syntax for view logic can get kind of verbose, especially when you're doing repetitive things like displaying defaults for each piece of data you've got that's not set, like so:

<% if @user.name %>
<%= @user.name %>
<% else %>
<em>[no name set]</em>
<% end %>

If you have to do that four or five times on a page, then all of a sudden you've got a template that is getting long and hard to follow.

Here's a quick little trick to handle that kind of situation much more concisely and clearly. It takes advantage of the fact that Ruby almost always provides multiple different ways to accomplish the same thing using different syntaxes. In this case, we'll use a very dense C-style if-then syntax that Ruby supports, which uses a ternary operator (the section on this syntax is well down that page, if you search for "c-style" it should pop right up). It looks like this:

condition ? if_true : if_false

or, in the case of our view logic from above:

<%= @user.name ? @user.name : "<em>[no name set]</em>" %>

How does this work? Ruby evaluates the expression to the left of the question mark. If that expression is true then it returns the expression between the question mark and the colon, if the expression is false, it returns what comes after the colon. Simple. And suddenly we've lost a lot of lines and lot of potential places for confusion from our views.

Like with anything else, there are a couple of small gotchas to look out for. First of all, you've got to make sure that the attribute you're evaluating on (in our case @user.name) will return either nil or false if it's not set. If it has any kind of default value, it will return true and then your conditional expression will do exactly the opposite of what you were expecting. The other danger here is making sure you use proper parentheses if you have any kind of a compound statement as the conditional as either of the outcome. Without them, things can get confusing in a hurry.

This may seem like a small change, but it will make every time you comeback to look at your views in the future and have to figure out what's going on in them from scratch more pleasant. It's also just the Rails thing to do: less code where possible, and code that feels 'beautiful' to you where it's not.

Tagged: , , , ,