views:

73

answers:

3

In my Rails application I'm trying to make the controllers skinnier and am having difficulty with one object that I keep having to pass around.

The object represents a user's facebook session and is instantiated off of the session so it exists in the controller side of things. Many model methods use it, so it is repeatedly passed in as an argument all over the place.

This smells like something, how to DRY it up the Rails way? Thanks!

+1  A: 

I can give you the CakePHP way (which was originally designed to be like rails).

All CakePHP models extend the same parent AppModel, and all controllers extend an AppController.

I would make an empty parameter in the AppModel that represents your object. Then in the AppController I would store the object in the current model's parameter, if the object exists. There is a callback in the CakePHP AppController called beforeFilter() which fires before any code in the controller. The ideal place to check for the object and store it in the model would be in whatever equivalent Rails has of this beforeFilter callback.

That is unless all models don't use the object. If that is true, you could put the parameter in only the Models that use it (instead of the parent), and then in the beforeFilter of the AppModel you can check first if the Model has that empty parameter.

I know it's not Ruby, but it would look like this:

public function beforeFilter() {
    if (isset($this->{$this->modelName}->yourObjectParameter)) {
        $this->{$this->modelName}->yourObjectParameter = $this->yourObject;
    }
}

$this->modelName is a string that corresponds to the name of the current model. the { } around $this->modelName in PHP is called complex syntax. It basically converts the string into the model object. Not sure how to do the same thing in Ruby.

Stephen
cool thanks. Yeah I was thinking of a before_filter to do a "if Model.object isn't there, set it for use". I guess one can take it even further by extending the models' superclass with the object. I do wonder if Rails has obscure "railsy-way" as I so often discover the case :)
ambertch
Yeah, that happens to me all the time. I work out a DRY solution on my own and then Bam! There was already a CakePHP method for that. ;)
Stephen
A: 

Hi ambertch

You can take your method to application controller, something like this

class ApplicationController < ActionController::Base

before_filter :get_facebook_session

def get_facebook_session

@facebook_session = <your code >

end

end

And you can access @facebook_session variable from your controllers and views

cheers

sameera

sameera207
This does not address the issue of passing it in to the models, which is what was causing the code smell.
Mike Trpcic
+1  A: 

First, I would recommend using a system similar to Authlogic for your authentication. This gives you two bonuses:

  • You have proven, stable, tested authentication for your application
  • The sessions are based like Models, so you can do this kind of stuff...

class Widget < ActiveRecord::Base
  def do_facebook_stuff
    UserSession.find #This gets you the current session
    UserSession.find.record # This gets your the user for the current session
  end
end

Now you no longer need to pass the session information in, as you can do basic model-style lookups to find it. In addition to this, Authlogic has a plugin architecture that supports Facebook Connect, which may help you further.

Mike Trpcic
Thanks Mike. I was on Authlogic+plugins before. I migrated to a users' identity being tied completely to Facebook, so the salting and password handling Authlogic provides became extraneous and I took out. I ended up just extracting some of authlogic's plugins' features into filter methods. Are there other advantages to putting in devise/authlogic I might be missing out on?
ambertch
actually, I'm really stupid - I was passing in this session b/c I needed the OAuth access token I embed in it, and not all users have one (some are "fake" users). HOWEVER, I have a architectural guarantee that any model method I pass in that needs the session's access token, has access to a user with access token. Thanks again Mike, your response helped me think things through.
ambertch