Skip to content

Commit

Permalink
improve behavior of nil powers; improve README
Browse files Browse the repository at this point in the history
  • Loading branch information
triskweline committed Dec 14, 2012
1 parent 129bb05 commit 40a58de
Show file tree
Hide file tree
Showing 4 changed files with 116 additions and 16 deletions.
60 changes: 58 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Consul is a authorization solution for Ruby on Rails that uses scopes to control

We have used Consul in combination with [assignable_values](https://github.com/makandra/assignable_values) to solve a variety of authorization requirements ranging from boring to bizarre.

Also see our crash course video: [Solving bizare authorization requirements with Rails](http://bizarre-authorization.talks.makandra.com/).


Describing a power for your application
---------------------------------------
Expand Down Expand Up @@ -61,8 +63,8 @@ You can also write power checks like this:

power.include?(:notes)
power.include!(:notes)
power.include?(:note, Note.last)
power.include!(:note, Note.last)
power.include?(:notes, Note.last)
power.include!(:notes, Note.last)


Boolean powers
Expand All @@ -85,6 +87,60 @@ You can query it like the other powers:
power.dashboard! # => raises Consul::Powerless unless Power#dashboard? returns true


Powers that give no access at all
---------------------------------

Note that there is a difference between having access to an empty list of records, and having no access at all.
If you want to express that a user has no access at all, make the respective power return `nil`.

Note how the power in the example below returns `nil` unless the user is an admin:

class Power
...

power :users do
User if @user.admin?
end

end

When a non-admin queries the `:users` power, she will get the following behavior:

power.notes # => returns nil
power.notes? # => returns false
power.notes! # => raises Consul::Powerless
power.note?(Note.last) # => returns false
power.note!(Note.last) # => raises Consul::Powerless


Other types of powers
---------------------

A power can return any type of object. For instance, you often want to return an array:

class Power
...

power :assignable_note_states do
if admin?
%w[draft pending published retracted]
else
%w[draft pending]
end
end

end

You can query it like any other power. E.g. if a non-admin queries this power she will get the following behavior:

power.assignable_note_states # => ['draft', 'pending']
power.assignable_note_states? # => returns true
power.assignable_note_states! # => does nothing (because the power isn't nil)
power.assignable_note_state?('draft') # => returns true
power.assignable_note_state?('published') # => returns false
power.assignable_note_state!('published') # => raises Consul::Powerless


Role-based permissions
----------------------

Expand Down
4 changes: 3 additions & 1 deletion lib/consul/power.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ def include?(name, *args)
if record.nil?
!!power_value
else
if scope?(power_value)
if power_value.nil?
false
elsif scope?(power_value)
power_ids_name = self.class.power_ids_name(name)
send(power_ids_name, *args).include?(record.id)
elsif collection?(power_value)
Expand Down
2 changes: 1 addition & 1 deletion lib/consul/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Consul
VERSION = '0.4.1'
VERSION = '0.4.2'
end
66 changes: 54 additions & 12 deletions spec/shared/consul/power_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,60 @@

end

context 'nil powers' do

describe '#include?' do

context 'when no record is given' do

it 'should return false' do
@user.role = 'guest'
@user.power.clients.should be_nil
@user.power.clients?.should be_false
end

end

context 'with a given record' do

it 'should return false' do
client = Client.create!
@user.role = 'guest'
@user.power.clients.should be_nil
@user.power.client?(client).should be_false
end

end

end

describe '#include!' do

context 'when no record is given' do

it 'should raise Consul::Powerless when the power returns nil' do
@user.role = 'guest'
@user.power.clients.should be_nil
expect { @user.power.clients! }.to raise_error(Consul::Powerless)
end

end

context 'with a given record' do

it 'should raise Consul::Powerless when' do
client = Client.create!
@user.role = 'guest'
@user.power.clients.should be_nil
expect { @user.power.client!(client) }.to raise_error(Consul::Powerless)
end

end

end

end

context 'scope powers' do

it 'should return the registered scope' do
Expand All @@ -40,12 +94,6 @@
@user.power.clients?.should be_true
end

it 'should return false if the power returns nil' do
@user.role = 'guest'
@user.power.clients.should be_nil
@user.power.clients?.should be_false
end

end

context 'with a given record' do
Expand All @@ -72,12 +120,6 @@

context 'when no record is given' do

it 'should raise Consul::Powerless when the power returns nil' do
@user.role = 'guest'
@user.power.clients.should be_nil
expect { @user.power.clients! }.to raise_error(Consul::Powerless)
end

it 'should not raise Consul::Powerless when the power returns a scope (which might or might not match records)' do
expect { @user.power.clients! }.to_not raise_error
end
Expand Down

0 comments on commit 40a58de

Please sign in to comment.