On Sat, Feb 28, 2009 at 4:34 PM, Zach Dennis <zach.den...@gmail.com> wrote:
> > Disclaimer, this entire post has to deal with model level > authorization and a technique I've been using and evolving in Rails > projects. It has nothing to do with your issue of global state for > what User is logged in. Onto the fun stuff IMO.... It's actually a lot closer to what I'm trying to get to the bottom of than the global variable bit is. > > > I've been wanting to write a thorough blog post on thoughts and > reflections on a very related topic, but since you've already kicked > off the conservation I'll try to add to the discussion. :) > > For nearly a year I've been utilizing the concepts of Roles and also > Privileges. They are close at heart, but different needs have proven > both of them to be successful at different times. > > Here's an example of being reliant on a role: > > # raises if the user cannot fulfill the role > supervisor = user.in_role(:supervisor) > supervisor.do_supervisory_thing > Okay. There actually is something fairly close to this. Take a group blog with an editor/supervisor. Anyone can write up and draft a document, but only the supervisor can publish it. Right now, I do have a User#is_supervisor_of?(group) method. Good enough there. Problem is, where does that check _happen_ ? At the model level? Or in the controller? You can externalize the request in the controller: if current_user.is_supervisor_of?( document.group) document.published_by = current_user document.publish! else # flag some errors end But if it's the sort of action that finds itself in a couple of different controllers, there's been a worry about repetition -- forgetting logic and such. Which is why the code is really more like this: # in the model def publish! if User.current.is_supervisor_of?(group) self.published_by = User.current self.state = 'published' else raise NotASupervisorError end end Only it's actually a bit worse than that, because I think it's wormed it's way into the validations... No controller can forget to check the authorization. However, it makes setting up test data -- and even working from the console -- painful. Among other things, there a business rule in place that you can't approve your own document. > > And the supervisor role looks like: > > class Roles::Supervisor < Roles::Base > def do_supervisory_thing > # inside the implementation you > # can refer to the source of the role > # using the method #source > end > end > > The privilege functionality is similar: > > # this will raise access denied if user doesn't have the privilege > payer = user.with_privilege(:make_payment) > payer.pay!(invoice) > > And its implementation looks like: > > class Privileges::MakePayment < Privileges::Base > def pay!(invoice) > Payment.create! :invoice => invoice > end > end > > This abstracts out the behaviour surrounding privileges and roles out > into their own component. In most cases the methods are very small, > and they merely create real models, or do other things. The big win > for me has been that they create a concrete representation of > something tied to a role or a privilege. I don't know how much more > intention-revealing I can get. :) > > Right now I am leaving things a little verbose in the controller > actions, e.g. user.in_role(...) or user.with_privilege(...), but I > like it because no one has to guess what is being used. The less > verbose route would be to omit #in_role or #with_privilege and just > say: > > user.pay!(invoice) > > The user would be in charge of searching its roles/privileges for one > that responded to #pay!. I am considering moving to this route, there > are some edge cases that would need to be solved. > > If you're interested, the roles project is on github: > http://github.com/zdennis/roles/tree/master > > I just through up a wiki page for using them with Rails if you want to > test it out: http://wiki.github.com/zdennis/roles/rails > I'll give it a read, see what I can learn > -- > Zach Dennis > http://www.continuousthinking.com > http://www.mutuallyhuman.com > _______________________________________________ > rspec-users mailing list > rspec-users@rubyforge.org > http://rubyforge.org/mailman/listinfo/rspec-users > -- // anything worth taking seriously is worth making fun of // http://blog.devcaffeine.com/
_______________________________________________ rspec-users mailing list rspec-users@rubyforge.org http://rubyforge.org/mailman/listinfo/rspec-users