To add, all of our managers return LoginResult objects which contain methods like:
- successful? - user - message In the controller our code will look like: if login.successful? self.current_user = login.user else flash[:error] = login.message end This has worked well because it allows each our types of logins to generate an accurate login message based on the type of login. For example when a user logs in from a session you don't need a message, but after someone logs in with their credentials you may want to say "You've successfully logged in". I like this approach because it removes responsibility away from the controller, and it makes things much easier to test (and to understand IMO). And you have a very readable API, Zach On Jan 11, 2008 12:49 PM, Zach Dennis <[EMAIL PROTECTED]> wrote: > We pass the required items in as method arguments. In the spirit of > sharing code and getting people to review code. Here is our current > LoginManager: > > class LoginManager > include Injection > inject :invitation_manager > > def login_from_cookie(cookies, session) > CookieLoginManager.new( > :cookies => cookies, > :session => session, > :invitation_manager => @invitation_manager > ).login > end > > def login_from_session(session) > SessionLoginManager.new( > :session => session, > :invitation_manager => @invitation_manager > ).login > end > > def login_with_credentials(options, session, cookies) > UserCredentialsLoginManager.new( > :options => options, > :session => session, > :cookies => cookies, > :invitation_manager => @invitation_manager > ).login > end > > def login_from_password_reset(user, session) > PasswordResetLoginManager.new( > :user => user, > :session => session > ).login > end > > def login_from_signup(user, session) > SignupLoginManager.new( > :user => user, > :session => session, > :invitation_manager => @invitation_manager > ).login > end > > end > > > The reason we did this in the first place was that we needed to be > able to add functionality (accepting invitations) to the login process > and it seemed to get ugly without having it isolated in it's own > object. We use additional login managers behind the scenes to have > simple testable objects for each type of login we do. > > The "Injection" module just lets us pull out existing objects from a > global app content and assign them as instance variables. That is how > we are getting reference to invitation manager. > > Zach > > > On Jan 11, 2008 12:45 PM, Ben Mabey <[EMAIL PROTECTED]> wrote: > > > > Zach Dennis wrote: > > > On Jan 11, 2008 11:56 AM, David Chelimsky <[EMAIL PROTECTED]> wrote: > > > > > >> On Jan 11, 2008 9:54 AM, Ben Mabey <[EMAIL PROTECTED]> wrote: > > >> > > >>> David Chelimsky wrote: > > >>> > > >>>> In TDD there is a rule of thumb that says don't stub a method in the > > >>>> same class as the method you're testing. The risk is that as the real > > >>>> implementation of by_input_sets!() changes over time, it has access to > > >>>> internal state that could impact the behaviour of decompose!(). > > >>>> > > >>>> > > >>> So, stubbing a current_user method on a rails controller would be > > >>> considered bad practice? > > >>> I suppose stubbing the find on User would be just as easy but I have > > >>> always just stubbed controller.current_user. > > >>> > > >> Rails is tricky. These rules are stem from situations in which you are > > >> in complete control of the design. Clearly, Rails makes it easy to > > >> work with if you follow its conventions, but the resulting design is > > >> far from Object Oriented. This is not an inherently bad thing - don't > > >> get me wrong. I use Rails and it's a delight in terms of development. > > >> But it's a challenge in terms of this kind of testing. > > >> > > >> That said, the User class object is a different object than a user > > >> instance, so I have no issue w/ stubbing find on it. > > >> > > >> As for controller.current_user, a purist TDD view would have you move > > >> that behaviour elsewhere. I break the rule and just stub it directly. > > >> This general advice I learned from Uncle Bob Martin: sometimes you > > >> have to break the rules, but when you do you should do it consciously > > >> and feel dirty about it ;) > > >> > > > > > > On the current project we've quit moved all authentication into a > > > LoginManager. This has worked out so nicely as we have simple methods > > > for: login_from_cookie, login_from_session, > > > login_from_user_credentials, etc. > > > > > > This cleans up a lot of the hairy code sprinkled throughout > > > controllers and before filters which were trying to do some form of > > > authentication based on peeking at the sessions themselves or > > > validating users. > > > > > > > > Interesting, do you pass in the session in the constructor or how do you > > get access to the session data? > > > > -Ben > > > > > > > -- > Zach Dennis > http://www.continuousthinking.com > -- Zach Dennis http://www.continuousthinking.com _______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users