Avoid Variable Collisions in Rails Controllers
Rails is by and large developer-friendly. But when bugs do arise, they have the potential to be nasty—at least until one becomes familiar with the techniques of Ruby debugging, which often require more subtlety than a less-dynamic language like Java or a language with more powerful introspection like Smalltalk.
Over the past 3 years of intensive ruby programming, the most gut-wrenchingly bizarre bugs I’ve encountered have usually had to do with name collisions. One reason is because Ruby allows opening of classes at will and because Rails is not warning-friendly (ie. Rails is not run with the ruby -w
flag), it’s exceedingly easy to clobber existing functions to all manner of bizarre effect. Keeping this potential in the back of one’s mind makes problems 90% easier to deal with when they come, which in my experience is rare but regular.
A simpler form of name collision occurs with instance variables, of which Rails uses a liberal sprinkling. Now for a long time the official word has been to avoid directly using instance variables provided by Rails, but the more important corollary has been neglected: Don’t clobber Rails internal instance variables. This is probably something that warrants a section in the documentation. For instance, setting any of these instance variables for application purposes is likely to cause problems:
- @url
- @template
- @assigns
- @_session
- @_request
- @_params
- @_cookies
- @_response
- @_headers
- @controller_class_name
- @controller_name
- @controller_path
- @view_paths
- @performed_render
- @performed_redirect
- @action_name
- @action_methods
- @variables_added
- @request_origin
Keep in mind these are just the variables from the ActionController::Base
file, but there are other instance variables mixed in from the various ActionController components. Some of these are more likely to be clobbered than others, but when you accidentally use one of them there’s really no telling what will happen. I used @url in a production project months ago, and only discovered the problem when I added an explicit query string parameter to a named url helper in my project’s layout, resulting in deep and somewhat perplexing breakage.
Clearly this situation could be improved at the framework level in a variety of ways, but I’ll stop short of recommending a solution. Simply being aware of the issue can save a lot of costly debugging time, so this note is here as a reminder to myself and others.
Joe Grossberg says…
April 12, 2008 at 4:42AM
Rails isn’t the only language.
I’ve seen #URL# clobber stuff in ColdFusion, not to mention the danger of register_globals in PHP.
Joe Grossberg says…
April 12, 2008 at 4:42AM
Err, framework, not language.