On Sat, Feb 28, 2009 at 4:34 PM, Zach Dennis <[email protected]> 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
> [email protected]
> http://rubyforge.org/mailman/listinfo/rspec-users
>
--
// anything worth taking seriously is worth making fun of
// http://blog.devcaffeine.com/
_______________________________________________
rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users