Dave Schweisguth in a Bottle

How many meanings of that can you think of?

Controller instance variables in Rails partials

leave a comment »

A model value in a Rails partial can be a controller @instance variable or a local variable passed in by the calling template. What should it be?

Some model values must vary within a single page, so can’t be instance variables. Even when instance variables can be used, they still smell bad to the careful coder, because they have broad scope — they’re visible to every template that makes up the page. However, the controlled scope of a local comes with a cost: the template that sets it must know about it, which means more coupling between the partial and the calling template. If the partial’s locals change, so must the calling template, and perhaps its caller and its caller. For a widely-used partial, this is a lot of work. With instance variables, the caller knows nothing, and the partial can change without ripples.

So, when can you take advantage of the convenience and reduced coupling of passing model values to a partial via instance variables?

  • If a partial is only used by one template, and is only used once by that template (to break the template into pieces of manageable size, or to take advantage of Rails’ implicit iteration over collections), scope isn’t an issue. Use instance variables.
  • It also makes sense to use instance variables if, although a partial is called by multiple templates, the values it needs are really global to the application. A partial like this probably appears on many or all of your app’s pages, and its values are probably set in one place in controller code (or should be). Examples are a partial which displays a user’s logged-in status, or one which includes analytics Javascript in the page. Because partials like this are used in many places, they’re where reducing coupling will pay off the most.
  • If a partial is used by multiple pages for different reasons, use locals. Each time you use the partial you’ll need to know what values it wants, and it will be easy to do so by looking at an existing use. If the partial used instance variables, you’d need to read all of it to see which ones, and if you needed to change them you’d have to do so in multiple templates and controllers.
  • In a partial which is used more than once on a page, each time with a different value, you have no choice; use locals. For example, you might have a partial that renders an ad, whose size and position on the page only the calling template would know.

In any case, use only instance variables or only locals in a given partial, not both. Whether a given model value should be an instance variable or a local is really specific to that value, but if a partial needs both globals and locals I’d suspect that it does unrelated things and should be broken up. A mixture of globals and locals will also be hardest for the next guy along to use correctly.

There is already, by the way, a decent discussion of this topic on Stack Overflow, but I’m a little more pro-partial than some (to my surprise, as I’m usually a miser with scope) and the topic has come up for me in several different contexts so it seemed worth tying a bow on it in this post.

In fact, there’s an exact analogy in Java Server Pages, where JSP variables, tags and tag attributes play the same roles that partials, controller instance variables and locals do in Rails. There’s a bit of an additional incentive to use tag attributes in JSP: they’re both typed, so your IDE and your JSP compiler can catch errors as you edit and when you compile, and optional, so callers can omit attributes which have sensible defaults. The type of a JSP variable can be specified too, with a jsp:useBean tag, but only if the variable is guaranteed to be present; tag attributes are therefore easier to work with. But long lists of required tag attributes are just as painful as are long list of locals in Rails, and recent versions of IntelliJ IDEA (the only tool I’d consider using to edit JSPs) can indicate the type of a model variable with a special comment, so it still makes sense to use JSP variables in the same situations in which you’d use controller instance variables in Rails.


Written by dschweisguth

February 22, 2011 at 18:00

Posted in Programming, Rails, Ruby

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: