Ruby on Rails Session in Models: Not So Evil Actually

I just finished reading this post from m.onkey.org on how to put your session into your models. First off, I love this guy, and his site, and most of what he says, but I’ve had it up to here with this nonsense. I also kind of felt a little dissed by the PHP comment. I understand he was joking, and it was kind of funny, PHP programmers are NOTORIOUS for using $_SESSION to store EVERYTHING. At the same time, as Voorhaus says, all comedy is truth and pain, and the truth is that PHP programmers do that, and the pain is that many programmers coming to Ruby and Rails feel alienated by that community because they are so opinionated (And not always right). Rails is kind of Opinionated by design, and that’s okay, but more often than not, the Rails and Ruby community is uneccessarily sadistic in its treatment of contradictory opinions, they have a “my way or the highway” kind of speech when in fact, you can do it anyway you want, and all they are doing is looking like douche bags for treating you as a sub-human for having a contradictory opinion. As I see it, at the core of the above issue, sessions in the model, is global variables, and the irrational fear of them.

Phear Globalz

There is some practicality in not depending on global variables, especially when you are TALKING about programming. When you are doing it, it’s another story. They can theoretically be the source of problems. Yes I understand that Global variables can be seen as a system design flaw and are an incorrect implementation of MVC separation and a violation of Dependency Injection (Kind of). Why? Because your domain logic shouldn’t depend on the state of other aspects of the system to work. All external data and instances needed by a particular class/object should be provided (Injected) into the model from the outside.

All relevant information needed by the Model is SUPPOSED to be provided to it during a method call FROM the Controller. Pretty much full stop. You aren’t supposed to instantiate classes inside a Model method, class instances should be given to the Model from the Controller.

This is because Objects in OOP are more than just Glorified Namespaces, which admittedly is how most novice programmers use them. They seem to be just a clever way to collect up functions and variables. That’s a very limited, albeit functional, view of Objects in OOP.

Objects SHOULD always be decoupled completely from any kind of dependency of the actual System Architecture, what that means is the Implementation of domain logic in a Model, SHOULD not depend on, or be coupled to, the Implementation of the System as a whole, OR the architecture of ANY other part of the system, such as a Controller, or even a View.

That is: Objects should only contain methods and information that pertain to themselves! They are self aware only. You should be able to take an ActiveRecord model out of a Rails application and plug it into a console application without modification.

All things being equal, the rules of OOP clearly indicate that anything that violates the above is verboten.

Unfortunately, all things are not equal. And pretending like there isn’t this thing called “the real world” where code has to ship, and probably by 4pm today. The truth is, it’s bad design, plain and simple, don’t excuse it, because you really can’t. But when the heat is on, and deadlines loom, you don’t always have the time or inclination, or yes even ability to do it the right way.

I worked in Los Angeles in the game industry pulling 14 hour days of marathon coding, everyday was crunch day at this place, and I admit, I made some seriously flawed design decisions from an OOP standpoint. But the code shipped, and at the end of the day, as I like to say, if it works, it’s Arnis.

Jamie Zawinski is what I would call a duct-tape programmer. And I say that with a great deal of respect. He is the kind of programmer who is hard at work building the future, and making useful things so that people can do stuff. He is the guy you want on your team building go-carts, because he has two favorite tools: duct tape and WD-40. And he will wield them elegantly even as your go-cart is careening down the hill at a mile a minute. This will happen while other programmers are still at the starting line arguing over whether to use titanium or some kind of space-age composite material that Boeing is using in the 787 Dreamliner.

When you are done, you might have a messy go-cart, but it’ll sure as hell fly.

Joelonsoftware

When you want the session in your Model, it’s almost invariably because you are using the session as a kind of Global Data Store. That’s actually not very evil. As long as you aren’t storing Objects in it, which is in fact Evil and there is a special place in hell reserved for people who store anything but ints and strings in the session variable.

Using Global Variables is to modern OOP as sex was to Victorian Society, most people do it, but OOP guys just “don’t want to talk about it.” Admit you use Global Variables in your app to an OOPer and you might as well have just admitted you like tying girls to a St. Andrews Cross and flogging them while wearing only leather chaps. You’ll get about the same look anyway.

Good programmers use Gobal Variables too, why? Because more often than not, it’s the path of least resistance, and when you do this stuff for a living, you know, where you have to pay rent at the end of the month? It kind of focuses your priorities. Managers don’t grok what a Global Variable even is, they just see that you met your deadline and shipped code, and even better, that the code works, at least most of the time. While other guys are sitting around arguing about the best and most correct implementation that considers all the rules given in a presentation by <InsertNameOfProfessionalKeyNotSpeaker>, you are writing working code.

At the end of the day, Gettin’ ‘er done, is more important than Gettin’ ‘er done right.

Tha Kode

The code presented by m.onkey goes something like this:

Cool. Except, that’s actually not such a good idea…

If I am going to do something the wrong way, I will do it right wrong. I know, sounds oxymoronic, but using Globals is WRONG not STUPID.

This way, instead of opening up every single class and defining a method on it, we just have this central data locator class which can change it’s implementation over time without really affecting the Model code, it is, in effect, just another Model. But it models a kind of Global State, it stands between the Models of the Application and the Controller/REST architecture, bridging the information gap. It’s implemented as a Singleton so we don’t really need to instantiate it.

In a sense, our Global Variable, in this case we wanted session, or params, is really a kind of Data Source, like a table in the Database, so we create a model to interface with it. In my personal opinion, session and params should be considered Models in the rails architecture, params is simply a Read Only datasource. In my opinion, params should be a read/write global object that is read and modified during a request and is pushed onto every request.

What I mean is:

If you stop for a moment to break down any system into an MVC architecture, you can really think of practically everything in these terms. It’s a purest mentality, but one that is actually practical. It would seem that, like Voldemort, Rails developers aren’t as Pure Blood as they would like to think.

Is that the only way?

Actually no, it’s certainly not. I like the above because there are lots of variables and data that I might want to expose to the various models and I really like DRY, that is, Don’t Repeat Yourself. These other methods require that you repeat yourself.

  1. Add an attribute_accessor to the model.
  2. Add an attribute_accessor to the model as an extension/module in another file, or in a controller before_filter

To give you an example, let’s say you want to access the currently logged in user_id? You don’t want to open up every class, or even ActiveRecord and set that, you might only set that in the User Model.

PHP Style Global Variables with Rails

Finally, there’s the most obvious method, the one that you probably should have realized was there: Ruby supports global variables with the $ prefix. So you can do something like this:

So as always, if you are going to do something wrong, do it right wrong and make it as flexible and robust as you possibly can.

Cheers, and good luck!

About Jason

I am a 31 year old programmer living in the south of France. I currently work actively in the fields of Ruby/PHP/Javascript and server/website administration.
This entry was posted in Computer Science, General Computing, OOP, Ruby on Rails, Ruby on Rails, Tips and Tricks, Topics, Tutorials, Writings and tagged , , , , . Bookmark the permalink.
  • dude

    ActiveRecord::Base.class is just Class, is it some kind of joke ?

    • jasonrouge

      That was his code. I copied it directly…talk to him about it, not me…

  • Anonymous

    Wow!!! Thats really awesome!!! 🙂