Tuesday, November 21, 2006

Gotcha: Ruby Class Variable Scope is Global

While working on the authorization portion of an application, I was using a class variable to cache lookups of access rights throughout the duration of a users session. For various obscure reasons that are not relevant, I did not want to cache the rights on a session variable, so was using a class variable for this purpose. This technique worked nicely for a single web user and during functional testing, but failed miserably with two or more users.

As it turns out (as tested on Webrick and Mongrel), class variables are shared between web sessions (this holds true for controller classes and for models). Depending upon your prior language and platform background, this may not be news to you, but it was to me, as I beleived class variables were isolated by user session. To make matters worse, under both Mongrel and Webrick on a Windows machine, the class variables ARE isolated by user session. The problem did not manifest itself until the application was deployed to Linux at our hosting site.

Lessons learned:
  • Be careful about assumptions you bring with you from other languages and platforms.
  • Test for simultaneous multiple users - just running your unit, functional, and integration tests for a single user is not sufficient.
  • While the portability of Ruby and Rails code is magnificent, there is at least one subtle difference (probably more) between behavior on platforms.
  • I now have have one more reason for needing to buy a Mac for software development.
The good news is that this behavior opens the possibility of selectively sharing cached data between users on a single machine, although this topic needs exploration as there are possibly better methods for doing this.

See RubyCenteral here and here for good overviews of class variables. See RailsTips.org for an article explaining the difference between class variables and class instance variables.

3 comments:

Anonymous said...

Class Variable caveats: http://errtheblog.com/post/22

Thomas Lockney said...

Part of the problem is that you're confusing the language with the framework. Class variables are part of Ruby the language and are defined to be shared across instances of a class. Sessions are something that exist solely as a part of the web framework -- they are not part of the language. I would seriously recommend a closer study of Ruby so that you don't fall into traps like this in the future. The fact that the class variables were not shared should have been the part that surprised you.

Sam said...

under both Mongrel and Webrick on a Windows machine, the class variables ARE isolated by user session. The problem did not manifest itself until the application was deployed to Linux at our hosting site

If you're in development mode all is reloaded each time you make a request. Not in production mode.

Is you was in development mode under windows, and in production mode under linux... it's normal.