From 0f49b5478fa9da02e6e197826d30341415bba734 Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Tue, 17 Nov 2009 10:46:16 -0800 Subject: [PATCH] adding 'cannot?' method which performs opposite check of 'can?' - closes #1 --- CHANGELOG.rdoc | 2 ++ README.rdoc | 14 +++++++++----- lib/cancan/ability.rb | 4 ++++ lib/cancan/controller_additions.rb | 6 +++++- spec/cancan/ability_spec.rb | 4 ++++ spec/cancan/controller_additions_spec.rb | 5 +++-- 6 files changed, 27 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 6c5611b..6cf1e84 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,3 +1,5 @@ +* adding "cannot?" method to ability, controller, and view which is inverse of "can?" - see issue #1 + * BACKWARDS INCOMPATIBLE: use Ability#initialize instead of 'prepare' to set up abilities - see issue #4 *0.1.0* (Nov 16th, 2009) diff --git a/README.rdoc b/README.rdoc index 218c9f9..c6aa7b0 100644 --- a/README.rdoc +++ b/README.rdoc @@ -38,17 +38,17 @@ First define a class called Ability, place it in "models/ability.rb". This class is where all permissions will go. See the "Defining Abilities" section below for more information. -In the view layer you can access the current permissions at any point using the "can?" method. See "Checking Abilities" section below. +In the view layer you can access the current permissions at any point using the "can?" and "cannot?" methods. See "Checking Abilities" section below. <% if can? :update, @article %> <%= link_to "Edit", edit_article_path(@article) %> <% end %> -You can also use this method in the controller layer along with the "unauthorized!" method to restrict access. +You can also use these methods in the controller layer along with the "unauthorized!" method to restrict access. def show @article = Article.find(params[:id]) - unauthorized! unless can? :read, @article + unauthorized! if cannot? :read, @article end Setting this for every action can be tedious, therefore a before filter is also provided for automatically applying this setting to a RESTful style resource controller. @@ -135,6 +135,10 @@ You can also pass the class instead of an instance (if you don't have one handy) <%= link_to "New Project", new_project_path %> <% end %> +The "cannot?" method is for convenience and performs the opposite check of "can?" + + cannot? :destroy, @project + == Custom Actions @@ -148,7 +152,7 @@ There is no limit to what actions you can use to determine abilities. For exampl # projects_controller.rb def update - unauthorized! if params[:project][:upload_picture] && !can?(:upload_picture, @project) + unauthorized! if params[:project][:upload_picture] && cannot?(:upload_picture, @project) # ... end @@ -199,7 +203,7 @@ def test "user can only destroy projects which he owns" user = User.new ability = Ability.new(user) assert ability.can?(:destroy, Project.new(:user => user)) - assert !ability.can?(:destroy, Project.new) + assert ability.cannot?(:destroy, Project.new) end diff --git a/lib/cancan/ability.rb b/lib/cancan/ability.rb index 410f294..8b6eb52 100644 --- a/lib/cancan/ability.rb +++ b/lib/cancan/ability.rb @@ -21,6 +21,10 @@ module CanCan false end + def cannot?(*args) + !can?(*args) + end + def possible_actions_for(initial_action) actions = [initial_action] (@aliased_actions || default_alias_actions).each do |target, aliases| diff --git a/lib/cancan/controller_additions.rb b/lib/cancan/controller_additions.rb index 4459e9c..ec2a90a 100644 --- a/lib/cancan/controller_additions.rb +++ b/lib/cancan/controller_additions.rb @@ -1,7 +1,7 @@ module CanCan module ControllerAdditions def self.included(base) - base.helper_method :can? + base.helper_method :can?, :cannot? end def unauthorized! @@ -16,6 +16,10 @@ module CanCan (@current_ability ||= current_ability).can?(*args) end + def cannot?(*args) + (@current_ability ||= current_ability).cannot?(*args) + end + def load_resource # TODO this could use some refactoring unless params[:action] == "index" if params[:id] diff --git a/spec/cancan/ability_spec.rb b/spec/cancan/ability_spec.rb index a2b172d..0267198 100644 --- a/spec/cancan/ability_spec.rb +++ b/spec/cancan/ability_spec.rb @@ -81,4 +81,8 @@ describe CanCan::Ability do it "should not respond to prepare (now using initialize)" do @ability.should_not respond_to(:prepare) end + + it "should offer cannot? method which is simply invert of can?" do + @ability.cannot?(:tie, String).should be_true + end end diff --git a/spec/cancan/controller_additions_spec.rb b/spec/cancan/controller_additions_spec.rb index e6de319..1cadbd7 100644 --- a/spec/cancan/controller_additions_spec.rb +++ b/spec/cancan/controller_additions_spec.rb @@ -11,7 +11,7 @@ describe CanCan::ControllerAdditions do before(:each) do @controller_class = Class.new @controller = @controller_class.new - mock(@controller_class).helper_method(:can?) + mock(@controller_class).helper_method(:can?, :cannot?) @controller_class.send(:include, CanCan::ControllerAdditions) end @@ -26,10 +26,11 @@ describe CanCan::ControllerAdditions do @controller.current_ability.should be_kind_of(Ability) end - it "should provide a can? method which goes through the current ability" do + it "should provide a can? and cannot? methods which go through the current ability" do stub(@controller).current_user { :current_user } @controller.current_ability.should be_kind_of(Ability) @controller.can?(:foo, :bar).should be_false + @controller.cannot?(:foo, :bar).should be_true end it "should load the resource if params[:id] is specified" do