nathanl / authority

*CURRENTLY UNMAINTAINED*. Authority helps you authorize actions in your Rails app. It's ORM-neutral and has very little fancy syntax; just group your models under one or more Authorizer classes and write plain Ruby methods on them.
MIT License
1.21k stars 67 forks source link

Grouping actions #33

Closed brendon closed 11 years ago

brendon commented 11 years ago

Hi @nathanl, hope you're having a great day :)

I was wondering if there is any capability to group actions but still allow for fine grained checking of abilities.

For example, CUD actions could be grouped as :manage and R actions could be grouped as :view or something like that. It's arbitrary, but is it possible to do as the current code stands?

In my case I just have :view and :edit as abilities, but in the example of admin resources it'd be nice to have :manage instead (encompassing both :view and :edit) so that I can say manageble_by?. Right now I can just say viewable_by? and know that that implies editable_by? and therefore manageable_by? but it seems less clear.

I'm not sure if I've thought this through well enough though so any ideas are welcome. I'm only in this habit through using Cancan :)

nathanl commented 11 years ago

Sure, you can do that. The actions that come with Authority are only suggestions, really. It's meant to give you lots of freedom.

At the extreme end, you can, if you like, go into your config/initializers/authority.rb, remove everything from config.abilities and config.controller_action_map, and start over defining what you want in your application. When the application boots again, it will use your new configuration to metaprogram the methods you asked for into Authority::Abilities and Authority::UserAbilities and start checking your controller actions according to the map. All of that will start expecting your authorizers to have the methods you specified.

It's totally up to you. Authority is just there to help you tie it all together. :)

brendon commented 11 years ago

Thanks Nathan, that makes a lot of sense.

I think I was misinterpreting things a bit :) In practice it works well. I just came unstuck when trying to test the default method as you don't seem to be able to do:

expect(AdminAuthorizer).not_to be_managable_by(@user)

if the managable_by?(user) method doesn't exist in the Authorizer. I ended up testing for editable_by and viewable_by as these seem to route to the default method due to the configuration in the initialiser?

Hope that makes sense :)

On Wed, Apr 17, 2013 at 9:46 PM, Nathan Long notifications@github.comwrote:

Sure, you can do that. The actions that come with Authority are only suggestions, really. It's meant to give you lots of freedom.

At the extreme end, you can, if you like, go into your config/initializers/authority.rb, remove everything from config.abilitiesand config.controller_action_map, and start over defining what you want in your application. When the application boots again, it will use your new configuration to metaprogram the methods you asked for into Authority::Abilities and Authority::UserAbilities and start checking your controller actions according to the map. All of that will start expecting your authorizers to have the methods you specified.

It's totally up to you. Authority is just there to help you tie it all together. :)

— Reply to this email directly or view it on GitHubhttps://github.com/nathanl/authority/issues/33#issuecomment-16496554 .

nathanl commented 11 years ago

Brendon - rspec just translates your be_something directly to calling something?. If you tell it to expect something .to be_made_of_cheese, it will call made_of_cheese? on the object.

If you're going to be using can_manage to describe things, I'd suggest you do define managable_by? in the Authorizer, though.

brendon commented 11 years ago

Thanks Nathan, yep I figured that must have been the case. It's probably for the best that there isn't THAT much method_missing magic going on :)

Just in terms of technique, would you recommend testing be_editable_by and be_viewable_by if those two methods are just routed through to the default method. Or is it smarter to just test the default method? I'm thinking the second is a better idea given these look more like unit tests :)

On Sat, Apr 20, 2013 at 1:32 AM, Nathan Long notifications@github.comwrote:

Brendon - rspec just translates your be_something directly to calling something?. If you tell it to expect something .to be_made_of_cheese, it will call made_of_cheese? on the object.

If you're going to be using can_manage to describe things, I'd suggest you do define managable_by? in the Authorizer, though.

— Reply to this email directly or view it on GitHubhttps://github.com/nathanl/authority/issues/33#issuecomment-16653049 .

nathanl commented 11 years ago

I would test both of those methods individually, but in as DRY a way as possible. For example:

%w[editable viewable].each do |adjective|
  it "is #{adjective} by the foo_user" do
    expect(FooAuthorizer.send("#{adjective}_by?", foo_user)).to be_true
  end
end

I use this technique a lot. Even running rspec with --format doc, you still get very readable output. And more importantly, you're protected from unexpected changes; if editable_by behavior diverges, you'll know to either update your tests or fix the bug.

I discommend testing the default method directly. I don't think I made it private, but I probably should have, as it doesn't make sense as a message being sent to that class. FooAuthorizer.updatable_by?(user) is a sensible question; FooAuthorizer.default(user) doesn't make much sense to read.

brendon commented 11 years ago

Thanks Nathan, that's good to know :) I'll start testing them that way then :)

Have a great day!

On Mon, Apr 22, 2013 at 9:40 PM, Nathan Long notifications@github.comwrote:

Personally, I would test both of those methods individually, because if you assume they're handled by the default method, that may change in the future and your tests won't catch it. However, you can do this in a very DRY way. For example:

%w[editable viewable].each do |adjective| it "is #{adjective} by the foo_user" do expect(FooAuthorizer.send("#{adjective}_by?", foo_user)).to be_true endend I use this technique a lot. Even running rspec with --format doc, you still get very readable output. And more importantly, you're protected from unexpected changes; if editable_by behavior diverges, you'll know to either update your tests or fix the bug.

— Reply to this email directly or view it on GitHubhttps://github.com/nathanl/authority/issues/33#issuecomment-16773742 .