From 2ea73a90e01f05dee83344797027b71d6baf20b4 Mon Sep 17 00:00:00 2001 From: Chris Rice Date: Thu, 23 May 2013 15:50:27 -0500 Subject: [PATCH 01/22] Fixes nested ability conditions in issue #859 --- lib/cancan/model_adapters/active_record_adapter.rb | 4 ++-- .../model_adapters/active_record_adapter_spec.rb | 12 +++++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/cancan/model_adapters/active_record_adapter.rb b/lib/cancan/model_adapters/active_record_adapter.rb index 6856bb7b..372897cc 100644 --- a/lib/cancan/model_adapters/active_record_adapter.rb +++ b/lib/cancan/model_adapters/active_record_adapter.rb @@ -73,8 +73,8 @@ def tableized_conditions(conditions, model_class = @model_class) value.delete(k) nested[k] = v else - name = model_class.reflect_on_association(name).table_name.to_sym - result_hash[name] = value + table_name = model_class.reflect_on_association(name).table_name.to_sym + result_hash[table_name] = value end nested end diff --git a/spec/cancan/model_adapters/active_record_adapter_spec.rb b/spec/cancan/model_adapters/active_record_adapter_spec.rb index a51774c4..2d81a46b 100644 --- a/spec/cancan/model_adapters/active_record_adapter_spec.rb +++ b/spec/cancan/model_adapters/active_record_adapter_spec.rb @@ -6,6 +6,7 @@ describe CanCan::ModelAdapters::ActiveRecordAdapter do with_model :category do table do |t| + t.string "name" t.boolean "visible" end model do @@ -159,6 +160,15 @@ lambda { Article.accessible_by(@ability) }.should raise_error(CanCan::Error) end + it "should support more than one deeply nested conditions" do + @ability.can :read, Comment, :article => { + :category => { + :name => 'foo', :visible => true + } + } + expect { Comment.accessible_by(@ability) }.to_not raise_error + end + it "should not allow to check ability on object against SQL conditions without block" do @ability.can :read, Article, ["secret=?", true] lambda { @ability.can? :read, Article.new }.should raise_error(CanCan::Error) @@ -317,4 +327,4 @@ # adapter.matches_condition?(article1, :name.nlike, "%ello worl%").should be_false end end -end +end \ No newline at end of file From e87464b78e570d29d7b2b0fae3adf573d7d507f8 Mon Sep 17 00:00:00 2001 From: Victor Martinez Date: Thu, 21 Nov 2013 14:20:35 +0100 Subject: [PATCH 02/22] FIX: Variable collision prevents defining permissions with multiple nested conditions --- lib/cancan/model_adapters/active_record_adapter.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/cancan/model_adapters/active_record_adapter.rb b/lib/cancan/model_adapters/active_record_adapter.rb index 372897cc..639b8d80 100644 --- a/lib/cancan/model_adapters/active_record_adapter.rb +++ b/lib/cancan/model_adapters/active_record_adapter.rb @@ -73,8 +73,7 @@ def tableized_conditions(conditions, model_class = @model_class) value.delete(k) nested[k] = v else - table_name = model_class.reflect_on_association(name).table_name.to_sym - result_hash[table_name] = value + result_hash[model_class.reflect_on_association(name).table_name.to_sym] = value end nested end From c8aec290016810e23936e6b1e37aded830243d65 Mon Sep 17 00:00:00 2001 From: Savater Sebastien Date: Wed, 11 Dec 2013 16:20:23 +0100 Subject: [PATCH 03/22] Use scoped to avoid sql query execution --- lib/cancan/controller_resource.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cancan/controller_resource.rb b/lib/cancan/controller_resource.rb index 702fbcfb..727cd90d 100644 --- a/lib/cancan/controller_resource.rb +++ b/lib/cancan/controller_resource.rb @@ -177,7 +177,9 @@ def collection_instance def resource_base if @options[:through] if parent_resource - @options[:singleton] ? resource_class : parent_resource.send(@options[:through_association] || name.to_s.pluralize) + base = @options[:singleton] ? resource_class : parent_resource.send(@options[:through_association] || name.to_s.pluralize) + base = base.scoped if base.respond_to? :scoped + base elsif @options[:shallow] resource_class else From 5155f63802a81d18470cf607bda76cf88dc99906 Mon Sep 17 00:00:00 2001 From: Savater Sebastien Date: Thu, 12 Dec 2013 08:37:25 +0100 Subject: [PATCH 04/22] Avoid deprecation warning with AR 4 --- lib/cancan/controller_resource.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cancan/controller_resource.rb b/lib/cancan/controller_resource.rb index 727cd90d..24bc76e4 100644 --- a/lib/cancan/controller_resource.rb +++ b/lib/cancan/controller_resource.rb @@ -178,7 +178,7 @@ def resource_base if @options[:through] if parent_resource base = @options[:singleton] ? resource_class : parent_resource.send(@options[:through_association] || name.to_s.pluralize) - base = base.scoped if base.respond_to? :scoped + base = base.scoped if defined?(ActiveRecord) && ActiveRecord::VERSION::MAJOR == 3 base elsif @options[:shallow] resource_class From 375c0120da9ff0633a042cfe73d042997aa7256d Mon Sep 17 00:00:00 2001 From: Savater Sebastien Date: Thu, 12 Dec 2013 09:16:27 +0100 Subject: [PATCH 05/22] Update to pass specs --- lib/cancan/controller_resource.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cancan/controller_resource.rb b/lib/cancan/controller_resource.rb index 24bc76e4..5c771204 100644 --- a/lib/cancan/controller_resource.rb +++ b/lib/cancan/controller_resource.rb @@ -178,7 +178,7 @@ def resource_base if @options[:through] if parent_resource base = @options[:singleton] ? resource_class : parent_resource.send(@options[:through_association] || name.to_s.pluralize) - base = base.scoped if defined?(ActiveRecord) && ActiveRecord::VERSION::MAJOR == 3 + base = base.scoped if base.respond_to?(:scoped) && defined?(ActiveRecord) && ActiveRecord::VERSION::MAJOR == 3 base elsif @options[:shallow] resource_class From a1ba470702bea6b9b1738aa7f87f1e72ff30e480 Mon Sep 17 00:00:00 2001 From: rahul-tapali Date: Sun, 29 Dec 2013 09:03:20 +0530 Subject: [PATCH 06/22] Changing [].flatten to array wrapper method --- lib/cancan/controller_resource.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/cancan/controller_resource.rb b/lib/cancan/controller_resource.rb index 5c771204..d0b867f2 100644 --- a/lib/cancan/controller_resource.rb +++ b/lib/cancan/controller_resource.rb @@ -247,11 +247,11 @@ def instance_name end def collection_actions - [:index] + [@options[:collection]].flatten + [:index] + Array(@options[:collection]) end def new_actions - [:new, :create] + [@options[:new]].flatten + [:new, :create] + Array(@options[:new]) end private From d3e4fd7665e9e3e891d7175816a15e8d283052db Mon Sep 17 00:00:00 2001 From: Matt Glover Date: Sat, 7 Dec 2013 17:21:23 -0500 Subject: [PATCH 07/22] Do not execute the scope condition on class permission checks. @conditions.empty? calls ActiveRecord::Relation#empty? when a scoped condition is provided. ActiveRecord::Relation#empty? will query the database while CanCan only needs to check if conditions are set on the rule. --- lib/cancan/rule.rb | 2 +- .../model_adapters/active_record_adapter_spec.rb | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/cancan/rule.rb b/lib/cancan/rule.rb index c0415de8..422c49d0 100644 --- a/lib/cancan/rule.rb +++ b/lib/cancan/rule.rb @@ -38,7 +38,7 @@ def matches_conditions?(action, subject, extra_args) matches_conditions_hash?(subject) else # Don't stop at "cannot" definitions when there are conditions. - @conditions.empty? ? true : @base_behavior + conditions_empty? ? true : @base_behavior end end diff --git a/spec/cancan/model_adapters/active_record_adapter_spec.rb b/spec/cancan/model_adapters/active_record_adapter_spec.rb index 2d81a46b..eb413364 100644 --- a/spec/cancan/model_adapters/active_record_adapter_spec.rb +++ b/spec/cancan/model_adapters/active_record_adapter_spec.rb @@ -326,5 +326,17 @@ # adapter.matches_condition?(article1, :name.nlike, "%helo%").should be_true # adapter.matches_condition?(article1, :name.nlike, "%ello worl%").should be_false end + + it 'should not execute a scope when checking ability on the class' do + relation = Article.where(:secret => true) + @ability.can :read, Article, relation do |article| + article.secret == true + end + + # Ensure the ActiveRecord::Relation condition does not trigger a count query + stub(relation).count { fail 'Unexpected scope execution.' } + + expect { @ability.can? :read, Article }.not_to raise_error + end end -end \ No newline at end of file +end From ba5294d30fb4b4437a3453c03c890dc584b6bf7e Mon Sep 17 00:00:00 2001 From: Franco Catena Date: Wed, 8 May 2013 16:08:26 -0300 Subject: [PATCH 08/22] id_param now returns nil when the param is nil --- lib/cancan/controller_resource.rb | 10 +++++++--- spec/cancan/controller_resource_spec.rb | 6 ++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/lib/cancan/controller_resource.rb b/lib/cancan/controller_resource.rb index d0b867f2..d7ca4bfb 100644 --- a/lib/cancan/controller_resource.rb +++ b/lib/cancan/controller_resource.rb @@ -127,11 +127,15 @@ def authorization_action end def id_param + @params[id_param_key].to_s if @params[id_param_key] + end + + def id_param_key if @options[:id_param] - @params[@options[:id_param]] + @options[:id_param] else - @params[parent? ? :"#{name}_id" : :id] - end.to_s + parent? ? :"#{name}_id" : :id + end end def member_action? diff --git a/spec/cancan/controller_resource_spec.rb b/spec/cancan/controller_resource_spec.rb index 03f16bfb..b04c661c 100644 --- a/spec/cancan/controller_resource_spec.rb +++ b/spec/cancan/controller_resource_spec.rb @@ -407,6 +407,12 @@ class Section resource.send(:id_param).class.should == String end + it "should id param return nil if param is nil" do + @params.merge!(:action => "show", :the_project => nil) + resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project) + resource.send(:id_param).class.should == NilClass + end + it "should load resource using custom find_by attribute" do project = Project.create!(:name => "foo") @params.merge!(:action => "show", :id => "foo") From 44c2ca7b5342880a69bd85fcf2a46652e9f9c952 Mon Sep 17 00:00:00 2001 From: Franco Catena Date: Mon, 2 Dec 2013 13:18:02 -0300 Subject: [PATCH 09/22] treat ActiveRecord::Relation as Array --- .rbenv-version | 1 - lib/cancan/rule.rb | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 .rbenv-version diff --git a/.rbenv-version b/.rbenv-version deleted file mode 100644 index 651f0b9a..00000000 --- a/.rbenv-version +++ /dev/null @@ -1 +0,0 @@ -1.8.7-p357 diff --git a/lib/cancan/rule.rb b/lib/cancan/rule.rb index 422c49d0..2dfee776 100644 --- a/lib/cancan/rule.rb +++ b/lib/cancan/rule.rb @@ -111,7 +111,7 @@ def matches_conditions_hash?(subject, conditions = @conditions) else attribute = subject.send(name) if value.kind_of?(Hash) - if attribute.kind_of? Array + if attribute.kind_of? Array || attribute.kind_of?(ActiveRecord::Relation) attribute.any? { |element| matches_conditions_hash? element, value } else !attribute.nil? && matches_conditions_hash?(attribute, value) From d5a07325d7a77c3bffd10b69b3761b04ce483e18 Mon Sep 17 00:00:00 2001 From: Franco Catena Date: Mon, 2 Dec 2013 13:23:42 -0300 Subject: [PATCH 10/22] Fix typo --- lib/cancan/rule.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cancan/rule.rb b/lib/cancan/rule.rb index 2dfee776..610ae957 100644 --- a/lib/cancan/rule.rb +++ b/lib/cancan/rule.rb @@ -111,7 +111,7 @@ def matches_conditions_hash?(subject, conditions = @conditions) else attribute = subject.send(name) if value.kind_of?(Hash) - if attribute.kind_of? Array || attribute.kind_of?(ActiveRecord::Relation) + if attribute.kind_of?(Array) || attribute.kind_of?(ActiveRecord::Relation) attribute.any? { |element| matches_conditions_hash? element, value } else !attribute.nil? && matches_conditions_hash?(attribute, value) From bd755e2fe6fbcdcc7b270808e28bbd013c3d7387 Mon Sep 17 00:00:00 2001 From: Bryan Rite Date: Mon, 27 Jan 2014 10:25:12 -0800 Subject: [PATCH 11/22] Remove .rvmrc, use .ruby-version, and move to 1.9.3 --- .ruby-version | 1 + .rvmrc | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 .ruby-version delete mode 100644 .rvmrc diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..77fee73a --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +1.9.3 diff --git a/.rvmrc b/.rvmrc deleted file mode 100644 index 4032eb67..00000000 --- a/.rvmrc +++ /dev/null @@ -1 +0,0 @@ -rvm use 1.8.7@cancan --create From 8976293458a79b75e9b928ade81a33892fb122d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Nicklas=20and=20Nicklas=20Ramh=C3=B6j?= Date: Wed, 22 Aug 2012 14:54:28 +0200 Subject: [PATCH 12/22] Allow multiple abilities with associations There are two issues with the current way cancan handles associations: 1) Records are returned multiple times in some circumstances 2) Several defined abilities prevent some records to show up under certain circumstances This commit includes tests for both cases. It fixes both problems by changing `joins` to `includes` for the AR adapters. This could have performance implications, since `includes` will also select all columns in the associated records. We tried various ways of achieving the same thing using Arel directly, but were unable to make this work due to lack of support for outer joins in Rails 3.1. This closes issues #724, #566 and #613 --- .../model_adapters/active_record_adapter.rb | 4 ++-- .../active_record_adapter_spec.rb | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/cancan/model_adapters/active_record_adapter.rb b/lib/cancan/model_adapters/active_record_adapter.rb index 639b8d80..5ba8f0d2 100644 --- a/lib/cancan/model_adapters/active_record_adapter.rb +++ b/lib/cancan/model_adapters/active_record_adapter.rb @@ -101,9 +101,9 @@ def database_records elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins) mergeable_conditions = @rules.select {|rule| rule.unmergeable? }.blank? if mergeable_conditions - @model_class.where(conditions).joins(joins) + @model_class.where(conditions).includes(joins) else - @model_class.where(*(@rules.map(&:conditions))).joins(joins) + @model_class.where(*(@rules.map(&:conditions))).includes(joins) end else @model_class.scoped(:conditions => conditions, :joins => joins) diff --git a/spec/cancan/model_adapters/active_record_adapter_spec.rb b/spec/cancan/model_adapters/active_record_adapter_spec.rb index eb413364..27c7d99f 100644 --- a/spec/cancan/model_adapters/active_record_adapter_spec.rb +++ b/spec/cancan/model_adapters/active_record_adapter_spec.rb @@ -114,6 +114,24 @@ Comment.accessible_by(@ability).should == [comment1] end + it "should only read articles which are published or in visible categories" do + @ability.can :read, Article, :category => { :visible => true } + @ability.can :read, Article, :published => true + article1 = Article.create!(:published => true) + article2 = Article.create!(:published => false) + article3 = Article.create!(:published => false, :category => Category.create!(:visible => true)) + Article.accessible_by(@ability).should == [article1, article3] + end + + it "should only read categories once even if they have multiple articles" do + @ability.can :read, Category, :articles => { :published => true } + @ability.can :read, Article, :published => true + category = Category.create! + Article.create!(:published => true, :category => category) + Article.create!(:published => true, :category => category) + Category.accessible_by(@ability).should == [category] + end + it "should only read comments for visible categories through articles" do @ability.can :read, Comment, :article => { :category => { :visible => true } } comment1 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => true))) From cd04d232cbd6cd3295bd539b70c20e523a8daa7a Mon Sep 17 00:00:00 2001 From: Oleg German Date: Tue, 23 Jul 2013 21:08:46 +0400 Subject: [PATCH 13/22] removed rr, bump rspec version to 2.14, expect syntax, ruby 1.9.3/2.0.0 compatible --- .travis.yml | 2 + cancan.gemspec | 3 +- spec/cancan/ability_spec.rb | 283 +++++++++--------- spec/cancan/controller_additions_spec.rb | 100 ++++--- spec/cancan/controller_resource_spec.rb | 230 +++++++------- spec/cancan/exceptions_spec.rb | 22 +- spec/cancan/inherited_resource_spec.rb | 32 +- spec/cancan/matchers_spec.rb | 32 +- .../active_record_adapter_spec.rb | 143 +++++---- .../data_mapper_adapter_spec.rb | 3 +- .../model_adapters/default_adapter_spec.rb | 2 +- .../model_adapters/mongoid_adapter_spec.rb | 3 +- spec/cancan/rule_spec.rb | 16 +- spec/spec_helper.rb | 7 +- 14 files changed, 438 insertions(+), 440 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0c0a2782..b31a69b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,7 @@ rvm: - 1.8.7 + - 1.9.3 + - 2.0.0 - ree notifications: recipients: diff --git a/cancan.gemspec b/cancan.gemspec index 7240a245..eba87a7e 100644 --- a/cancan.gemspec +++ b/cancan.gemspec @@ -10,9 +10,8 @@ Gem::Specification.new do |s| s.files = Dir["{lib,spec}/**/*", "[A-Z]*", "init.rb"] - ["Gemfile.lock"] s.require_path = "lib" - s.add_development_dependency 'rspec', '~> 2.6.0' + s.add_development_dependency 'rspec', '~> 2.14.0' s.add_development_dependency 'rails', '~> 3.0.9' - s.add_development_dependency 'rr', '~> 0.10.11' # 1.0.0 has respond_to? issues: http://github.com/btakita/rr/issues/issue/43 s.add_development_dependency 'supermodel', '~> 0.1.4' s.rubyforge_project = s.name diff --git a/spec/cancan/ability_spec.rb b/spec/cancan/ability_spec.rb index 38595cb7..8d38103b 100644 --- a/spec/cancan/ability_spec.rb +++ b/spec/cancan/ability_spec.rb @@ -2,18 +2,17 @@ describe CanCan::Ability do before(:each) do - @ability = Object.new - @ability.extend(CanCan::Ability) + (@ability = double).extend(CanCan::Ability) end it "should be able to :read anything" do @ability.can :read, :all - @ability.can?(:read, String).should be_true - @ability.can?(:read, 123).should be_true + expect(@ability.can?(:read, String)).to be_true + expect(@ability.can?(:read, 123)).to be_true end it "should not have permission to do something it doesn't know about" do - @ability.can?(:foodfight, String).should be_false + expect(@ability.can?(:foodfight, String)).to be_false end it "should pass true to `can?` when non false/nil is returned in block" do @@ -21,15 +20,15 @@ @ability.can :read, Symbol do |sym| "foo" # TODO test that sym is nil when no instance is passed end - @ability.can?(:read, :some_symbol).should == true + expect(@ability.can?(:read, :some_symbol)).to be_true end it "should pass nil to a block when no instance is passed" do @ability.can :read, Symbol do |sym| - sym.should be_nil + expect(sym).to be_nil true end - @ability.can?(:read, Symbol).should be_true + expect(@ability.can?(:read, Symbol)).to be_true end it "should pass to previous rule, if block returns false or nil" do @@ -40,19 +39,19 @@ @ability.can :read, Integer do |i| i > 10 end - @ability.can?(:read, Symbol).should be_true - @ability.can?(:read, 11).should be_true - @ability.can?(:read, 1).should be_true - @ability.can?(:read, 6).should be_false + expect(@ability.can?(:read, Symbol)).to be_true + expect(@ability.can?(:read, 11)).to be_true + expect(@ability.can?(:read, 1)).to be_true + expect(@ability.can?(:read, 6)).to be_false end it "should not pass class with object if :all objects are accepted" do @ability.can :preview, :all do |object| - object.should == 123 + expect(object).to eq(123) @block_called = true end @ability.can?(:preview, 123) - @block_called.should be_true + expect(@block_called).to be_true end it "should not call block when only class is passed, only return true" do @@ -60,113 +59,113 @@ @ability.can :preview, :all do |object| @block_called = true end - @ability.can?(:preview, Hash).should be_true - @block_called.should be_false + expect(@ability.can?(:preview, Hash)).to be_true + expect(@block_called).to be_false end it "should pass only object for global manage actions" do @ability.can :manage, String do |object| - object.should == "foo" + expect(object).to eq("foo") @block_called = true end - @ability.can?(:stuff, "foo").should - @block_called.should be_true + expect(@ability.can?(:stuff, "foo")).to be_true + expect(@block_called).to be_true end it "should alias update or destroy actions to modify action" do @ability.alias_action :update, :destroy, :to => :modify @ability.can :modify, :all - @ability.can?(:update, 123).should be_true - @ability.can?(:destroy, 123).should be_true + expect(@ability.can?(:update, 123)).to be_true + expect(@ability.can?(:destroy, 123)).to be_true end it "should allow deeply nested aliased actions" do @ability.alias_action :increment, :to => :sort @ability.alias_action :sort, :to => :modify @ability.can :modify, :all - @ability.can?(:increment, 123).should be_true + expect(@ability.can?(:increment, 123)).to be_true end it "should raise an Error if alias target is an exist action" do - lambda{ @ability.alias_action :show, :to => :show }.should raise_error(CanCan::Error, "You can't specify target (show) as alias because it is real action name") + expect { @ability.alias_action :show, :to => :show }.to raise_error(CanCan::Error, "You can't specify target (show) as alias because it is real action name") end it "should always call block with arguments when passing no arguments to can" do @ability.can do |action, object_class, object| - action.should == :foo - object_class.should == 123.class - object.should == 123 + expect(action).to eq(:foo) + expect(object_class).to eq(123.class) + expect(object).to eq(123) @block_called = true end @ability.can?(:foo, 123) - @block_called.should be_true + expect(@block_called).to be_true end it "should pass nil to object when comparing class with can check" do @ability.can do |action, object_class, object| - action.should == :foo - object_class.should == Hash - object.should be_nil + expect(action).to eq(:foo) + expect(object_class).to eq(Hash) + expect(object).to be_nil @block_called = true end @ability.can?(:foo, Hash) - @block_called.should be_true + expect(@block_called).to be_true end it "should automatically alias index and show into read calls" do @ability.can :read, :all - @ability.can?(:index, 123).should be_true - @ability.can?(:show, 123).should be_true + expect(@ability.can?(:index, 123)).to be_true + expect(@ability.can?(:show, 123)).to be_true end it "should automatically alias new and edit into create and update respectively" do @ability.can :create, :all @ability.can :update, :all - @ability.can?(:new, 123).should be_true - @ability.can?(:edit, 123).should be_true + expect(@ability.can?(:new, 123)).to be_true + expect(@ability.can?(:edit, 123)).to be_true end it "should not respond to prepare (now using initialize)" do - @ability.should_not respond_to(:prepare) + expect(@ability).to_not respond_to(:prepare) end it "should offer cannot? method which is simply invert of can?" do - @ability.cannot?(:tie, String).should be_true + expect(@ability.cannot?(:tie, String)).to be_true end it "should be able to specify multiple actions and match any" do @ability.can [:read, :update], :all - @ability.can?(:read, 123).should be_true - @ability.can?(:update, 123).should be_true - @ability.can?(:count, 123).should be_false + expect(@ability.can?(:read, 123)).to be_true + expect(@ability.can?(:update, 123)).to be_true + expect(@ability.can?(:count, 123)).to be_false end it "should be able to specify multiple classes and match any" do @ability.can :update, [String, Range] - @ability.can?(:update, "foo").should be_true - @ability.can?(:update, 1..3).should be_true - @ability.can?(:update, 123).should be_false + expect(@ability.can?(:update, "foo")).to be_true + expect(@ability.can?(:update, 1..3)).to be_true + expect(@ability.can?(:update, 123)).to be_false end it "should support custom objects in the rule" do @ability.can :read, :stats - @ability.can?(:read, :stats).should be_true - @ability.can?(:update, :stats).should be_false - @ability.can?(:read, :nonstats).should be_false + expect(@ability.can?(:read, :stats)).to be_true + expect(@ability.can?(:update, :stats)).to be_false + expect(@ability.can?(:read, :nonstats)).to be_false end it "should check ancestors of class" do @ability.can :read, Numeric - @ability.can?(:read, Integer).should be_true - @ability.can?(:read, 1.23).should be_true - @ability.can?(:read, "foo").should be_false + expect(@ability.can?(:read, Integer)).to be_true + expect(@ability.can?(:read, 1.23)).to be_true + expect(@ability.can?(:read, "foo")).to be_false end it "should support 'cannot' method to define what user cannot do" do @ability.can :read, :all @ability.cannot :read, Integer - @ability.can?(:read, "foo").should be_true - @ability.can?(:read, 123).should be_false + expect(@ability.can?(:read, "foo")).to be_true + expect(@ability.can?(:read, 123)).to be_false end it "should pass to previous rule, if block returns false or nil" do @@ -174,20 +173,20 @@ @ability.cannot :read, Integer do |int| int > 10 ? nil : ( int > 5 ) end - @ability.can?(:read, "foo").should be_true - @ability.can?(:read, 3).should be_true - @ability.can?(:read, 8).should be_false - @ability.can?(:read, 123).should be_true + expect(@ability.can?(:read, "foo")).to be_true + expect(@ability.can?(:read, 3)).to be_true + expect(@ability.can?(:read, 8)).to be_false + expect(@ability.can?(:read, 123)).to be_true end it "should always return `false` for single cannot definition" do @ability.cannot :read, Integer do |int| int > 10 ? nil : ( int > 5 ) end - @ability.can?(:read, "foo").should be_false - @ability.can?(:read, 3).should be_false - @ability.can?(:read, 8).should be_false - @ability.can?(:read, 123).should be_false + expect(@ability.can?(:read, "foo")).to be_false + expect(@ability.can?(:read, 3)).to be_false + expect(@ability.can?(:read, 8)).to be_false + expect(@ability.can?(:read, 123)).to be_false end it "should pass to previous cannot definition, if block returns false or nil" do @@ -195,139 +194,139 @@ @ability.can :read, Integer do |int| int > 10 ? nil : ( int > 5 ) end - @ability.can?(:read, "foo").should be_false - @ability.can?(:read, 3).should be_false - @ability.can?(:read, 10).should be_true - @ability.can?(:read, 123).should be_false + expect(@ability.can?(:read, "foo")).to be_false + expect(@ability.can?(:read, 3)).to be_false + expect(@ability.can?(:read, 10)).to be_true + expect(@ability.can?(:read, 123)).to be_false end it "should append aliased actions" do @ability.alias_action :update, :to => :modify @ability.alias_action :destroy, :to => :modify - @ability.aliased_actions[:modify].should == [:update, :destroy] + expect(@ability.aliased_actions[:modify]).to eq([:update, :destroy]) end it "should clear aliased actions" do @ability.alias_action :update, :to => :modify @ability.clear_aliased_actions - @ability.aliased_actions[:modify].should be_nil + expect(@ability.aliased_actions[:modify]).to be_nil end it "should pass additional arguments to block from can?" do @ability.can :read, Integer do |int, x| int > x end - @ability.can?(:read, 2, 1).should be_true - @ability.can?(:read, 2, 3).should be_false + expect(@ability.can?(:read, 2, 1)).to be_true + expect(@ability.can?(:read, 2, 3)).to be_false end it "should use conditions as third parameter and determine abilities from it" do @ability.can :read, Range, :begin => 1, :end => 3 - @ability.can?(:read, 1..3).should be_true - @ability.can?(:read, 1..4).should be_false - @ability.can?(:read, Range).should be_true + expect(@ability.can?(:read, 1..3)).to be_true + expect(@ability.can?(:read, 1..4)).to be_false + expect(@ability.can?(:read, Range)).to be_true end it "should allow an array of options in conditions hash" do @ability.can :read, Range, :begin => [1, 3, 5] - @ability.can?(:read, 1..3).should be_true - @ability.can?(:read, 2..4).should be_false - @ability.can?(:read, 3..5).should be_true + expect(@ability.can?(:read, 1..3)).to be_true + expect(@ability.can?(:read, 2..4)).to be_false + expect(@ability.can?(:read, 3..5)).to be_true end it "should allow a range of options in conditions hash" do @ability.can :read, Range, :begin => 1..3 - @ability.can?(:read, 1..10).should be_true - @ability.can?(:read, 3..30).should be_true - @ability.can?(:read, 4..40).should be_false + expect(@ability.can?(:read, 1..10)).to be_true + expect(@ability.can?(:read, 3..30)).to be_true + expect(@ability.can?(:read, 4..40)).to be_false end it "should allow nested hashes in conditions hash" do @ability.can :read, Range, :begin => { :to_i => 5 } - @ability.can?(:read, 5..7).should be_true - @ability.can?(:read, 6..8).should be_false + expect(@ability.can?(:read, 5..7)).to be_true + expect(@ability.can?(:read, 6..8)).to be_false end it "should match any element passed in to nesting if it's an array (for has_many associations)" do @ability.can :read, Range, :to_a => { :to_i => 3 } - @ability.can?(:read, 1..5).should be_true - @ability.can?(:read, 4..6).should be_false + expect(@ability.can?(:read, 1..5)).to be_true + expect(@ability.can?(:read, 4..6)).to be_false end it "should accept a set as a condition value" do - mock(object_with_foo_2 = Object.new).foo { 2 } - mock(object_with_foo_3 = Object.new).foo { 3 } + expect(object_with_foo_2 = double(foo: 2)).to receive(:foo) + expect(object_with_foo_3 = double(foo: 3)).to receive(:foo) @ability.can :read, Object, :foo => [1, 2, 5].to_set - @ability.can?(:read, object_with_foo_2).should be_true - @ability.can?(:read, object_with_foo_3).should be_false + expect(@ability.can?(:read, object_with_foo_2)).to be_true + expect(@ability.can?(:read, object_with_foo_3)).to be_false end it "should not match subjects return nil for methods that must match nested a nested conditions hash" do - mock(object_with_foo = Object.new).foo { :bar } + (object_with_foo = double(foo: :bar)).should_receive(:foo) @ability.can :read, Array, :first => { :foo => :bar } - @ability.can?(:read, [object_with_foo]).should be_true - @ability.can?(:read, []).should be_false + expect(@ability.can?(:read, [object_with_foo])).to be_true + expect(@ability.can?(:read, [])).to be_false end it "should match strings but not substrings specified in a conditions hash" do @ability.can :read, String, :presence => "declassified" - @ability.can?(:read, "declassified").should be_true - @ability.can?(:read, "classified").should be_false + expect(@ability.can?(:read, "declassified")).to be_true + expect(@ability.can?(:read, "classified")).to be_false end it "should not stop at cannot definition when comparing class" do @ability.can :read, Range @ability.cannot :read, Range, :begin => 1 - @ability.can?(:read, 2..5).should be_true - @ability.can?(:read, 1..5).should be_false - @ability.can?(:read, Range).should be_true + expect(@ability.can?(:read, 2..5)).to be_true + expect(@ability.can?(:read, 1..5)).to be_false + expect(@ability.can?(:read, Range)).to be_true end it "should stop at cannot definition when no hash is present" do @ability.can :read, :all @ability.cannot :read, Range - @ability.can?(:read, 1..5).should be_false - @ability.can?(:read, Range).should be_false + expect(@ability.can?(:read, 1..5)).to be_false + expect(@ability.can?(:read, Range)).to be_false end it "should allow to check ability for Module" do module B; end class A; include B; end @ability.can :read, B - @ability.can?(:read, A).should be_true - @ability.can?(:read, A.new).should be_true + expect(@ability.can?(:read, A)).to be_true + expect(@ability.can?(:read, A.new)).to be_true end it "should pass nil to a block for ability on Module when no instance is passed" do module B; end class A; include B; end @ability.can :read, B do |sym| - sym.should be_nil + expect(sym).to be_nil true end - @ability.can?(:read, B).should be_true - @ability.can?(:read, A).should be_true + expect(@ability.can?(:read, B)).to be_true + expect(@ability.can?(:read, A)).to be_true end it "passing a hash of subjects should check permissions through association" do @ability.can :read, Range, :string => {:length => 3} - @ability.can?(:read, "foo" => Range).should be_true - @ability.can?(:read, "foobar" => Range).should be_false - @ability.can?(:read, 123 => Range).should be_true + expect(@ability.can?(:read, "foo" => Range)).to be_true + expect(@ability.can?(:read, "foobar" => Range)).to be_false + expect(@ability.can?(:read, 123 => Range)).to be_true end it "passing a hash of subjects with multiple definitions should check permissions correctly" do @ability.can :read, Range, :string => {:length => 4} @ability.can [:create, :read], Range, :string => {:upcase => 'FOO'} - @ability.can?(:read, "foo" => Range).should be_true - @ability.can?(:read, "foobar" => Range).should be_false - @ability.can?(:read, 1234 => Range).should be_true + expect(@ability.can?(:read, "foo" => Range)).to be_true + expect(@ability.can?(:read, "foobar" => Range)).to be_false + expect(@ability.can?(:read, 1234 => Range)).to be_true end it "should allow to check ability on Hash-like object" do class Container < Hash; end @ability.can :read, Container - @ability.can?(:read, Container.new).should be_true + expect(@ability.can?(:read, Container.new)).to be_true end it "should have initial attributes based on hash conditions of 'new' action" do @@ -335,16 +334,16 @@ class Container < Hash; end @ability.can :create, Range, :bar => 123, :array => %w[skip arrays] @ability.can :new, Range, :baz => "baz", :range => 1..3 @ability.cannot :new, Range, :ignore => "me" - @ability.attributes_for(:new, Range).should == {:foo => "foo", :bar => 123, :baz => "baz"} + expect(@ability.attributes_for(:new, Range)).to eq({:foo => "foo", :bar => 123, :baz => "baz"}) end it "should raise access denied exception if ability us unauthorized to perform a certain action" do begin @ability.authorize! :read, :foo, 1, 2, 3, :message => "Access denied!" rescue CanCan::AccessDenied => e - e.message.should == "Access denied!" - e.action.should == :read - e.subject.should == :foo + expect(e.message).to eq("Access denied!") + expect(e.action).to eq(:read) + expect(e.subject).to eq(:foo) else fail "Expected CanCan::AccessDenied exception to be raised" end @@ -352,25 +351,25 @@ class Container < Hash; end it "should not raise access denied exception if ability is authorized to perform an action and return subject" do @ability.can :read, :foo - lambda { - @ability.authorize!(:read, :foo).should == :foo - }.should_not raise_error + expect { + expect(@ability.authorize!(:read, :foo)).to eq(:foo) + }.to_not raise_error end it "should know when block is used in conditions" do @ability.can :read, :foo - @ability.should_not have_block(:read, :foo) + expect(@ability).to_not have_block(:read, :foo) @ability.can :read, :foo do |foo| false end - @ability.should have_block(:read, :foo) + expect(@ability).to have_block(:read, :foo) end it "should know when raw sql is used in conditions" do @ability.can :read, :foo - @ability.should_not have_raw_sql(:read, :foo) + expect(@ability).to_not have_raw_sql(:read, :foo) @ability.can :read, :foo, 'false' - @ability.should have_raw_sql(:read, :foo) + expect(@ability).to have_raw_sql(:read, :foo) end it "should raise access denied exception with default message if not specified" do @@ -378,26 +377,25 @@ class Container < Hash; end @ability.authorize! :read, :foo rescue CanCan::AccessDenied => e e.default_message = "Access denied!" - e.message.should == "Access denied!" + expect(e.message).to eq("Access denied!") else fail "Expected CanCan::AccessDenied exception to be raised" end end - it "should determine model adapter class by asking AbstractAdapter" do - model_class = Object.new - adapter_class = Object.new - stub(CanCan::ModelAdapters::AbstractAdapter).adapter_class(model_class) { adapter_class } - stub(adapter_class).new(model_class, []) { :adapter_instance } - @ability.model_adapter(model_class, :read).should == :adapter_instance + it "should determine model adapterO class by asking AbstractAdapter" do + adapter_class, model_class = double, double + allow(CanCan::ModelAdapters::AbstractAdapter).to receive(:adapter_class).with(model_class) { adapter_class } + allow(adapter_class).to receive(:new).with(model_class, []) { :adapter_instance } + expect(@ability.model_adapter(model_class, :read)).to eq(:adapter_instance) end it "should raise an error when attempting to use a block with a hash condition since it's not likely what they want" do - lambda { + expect { @ability.can :read, Array, :published => true do false end - }.should raise_error(CanCan::Error, "You are not able to supply a block with a hash of conditions in read Array ability. Use either one.") + }.to raise_error(CanCan::Error, "You are not able to supply a block with a hash of conditions in read Array ability. Use either one.") end describe "unauthorized message" do @@ -407,14 +405,14 @@ class Container < Hash; end it "should use action/subject in i18n" do I18n.backend.store_translations :en, :unauthorized => {:update => {:array => "foo"}} - @ability.unauthorized_message(:update, Array).should == "foo" - @ability.unauthorized_message(:update, [1, 2, 3]).should == "foo" - @ability.unauthorized_message(:update, :missing).should be_nil + expect(@ability.unauthorized_message(:update, Array)).to eq("foo") + expect(@ability.unauthorized_message(:update, [1, 2, 3])).to eq("foo") + expect(@ability.unauthorized_message(:update, :missing)).to be_nil end it "should use symbol as subject directly" do I18n.backend.store_translations :en, :unauthorized => {:has => {:cheezburger => "Nom nom nom. I eated it."}} - @ability.unauthorized_message(:has, :cheezburger).should == "Nom nom nom. I eated it." + expect(@ability.unauthorized_message(:has, :cheezburger)).to eq("Nom nom nom. I eated it.") end it "should fall back to 'manage' and 'all'" do @@ -422,37 +420,36 @@ class Container < Hash; end :manage => {:all => "manage all", :array => "manage array"}, :update => {:all => "update all", :array => "update array"} } - @ability.unauthorized_message(:update, Array).should == "update array" - @ability.unauthorized_message(:update, Hash).should == "update all" - @ability.unauthorized_message(:foo, Array).should == "manage array" - @ability.unauthorized_message(:foo, Hash).should == "manage all" + expect(@ability.unauthorized_message(:update, Array)).to eq("update array") + expect(@ability.unauthorized_message(:update, Hash)).to eq("update all") + expect(@ability.unauthorized_message(:foo, Array)).to eq("manage array") + expect(@ability.unauthorized_message(:foo, Hash)).to eq("manage all") end it "should follow aliased actions" do I18n.backend.store_translations :en, :unauthorized => {:modify => {:array => "modify array"}} @ability.alias_action :update, :to => :modify - @ability.unauthorized_message(:update, Array).should == "modify array" - @ability.unauthorized_message(:edit, Array).should == "modify array" + expect(@ability.unauthorized_message(:update, Array)).to eq("modify array") + expect(@ability.unauthorized_message(:edit, Array)).to eq("modify array") end it "should have variables for action and subject" do I18n.backend.store_translations :en, :unauthorized => {:manage => {:all => "%{action} %{subject}"}} # old syntax for now in case testing with old I18n - @ability.unauthorized_message(:update, Array).should == "update array" - @ability.unauthorized_message(:update, ArgumentError).should == "update argument error" - @ability.unauthorized_message(:edit, 1..3).should == "edit range" + expect(@ability.unauthorized_message(:update, Array)).to eq("update array") + expect(@ability.unauthorized_message(:update, ArgumentError)).to eq("update argument error") + expect(@ability.unauthorized_message(:edit, 1..3)).to eq("edit range") end end describe "#merge" do it "should add the rules from the given ability" do @ability.can :use, :tools - another_ability = Object.new - another_ability.extend(CanCan::Ability) + (another_ability = double).extend(CanCan::Ability) another_ability.can :use, :search @ability.merge(another_ability) - @ability.can?(:use, :search).should be_true - @ability.send(:rules).size.should == 2 + expect(@ability.can?(:use, :search)).to be_true + expect(@ability.send(:rules).size).to eq(2) end end end diff --git a/spec/cancan/controller_additions_spec.rb b/spec/cancan/controller_additions_spec.rb index cb8af3f1..c1ed6820 100644 --- a/spec/cancan/controller_additions_spec.rb +++ b/spec/cancan/controller_additions_spec.rb @@ -4,134 +4,138 @@ before(:each) do @controller_class = Class.new @controller = @controller_class.new - stub(@controller).params { {} } - stub(@controller).current_user { :current_user } - mock(@controller_class).helper_method(:can?, :cannot?, :current_ability) + allow(@controller).to receive(:params) { {} } + allow(@controller).to receive(:current_user) { :current_user } + expect(@controller_class).to receive(:helper_method).with(:can?, :cannot?, :current_ability) @controller_class.send(:include, CanCan::ControllerAdditions) end it "should raise ImplementationRemoved when attempting to call 'unauthorized!' on a controller" do - lambda { @controller.unauthorized! }.should raise_error(CanCan::ImplementationRemoved) + expect { @controller.unauthorized! }.to raise_error(CanCan::ImplementationRemoved) end it "authorize! should assign @_authorized instance variable and pass args to current ability" do - mock(@controller.current_ability).authorize!(:foo, :bar) + allow(@controller.current_ability).to receive(:authorize!).with(:foo, :bar) @controller.authorize!(:foo, :bar) - @controller.instance_variable_get(:@_authorized).should be_true + expect(@controller.instance_variable_get(:@_authorized)).to be_true end it "should have a current_ability method which generates an ability for the current user" do - @controller.current_ability.should be_kind_of(Ability) + expect(@controller.current_ability).to be_kind_of(Ability) end it "should provide a can? and cannot? methods which go through the current ability" do - @controller.current_ability.should be_kind_of(Ability) - @controller.can?(:foo, :bar).should be_false - @controller.cannot?(:foo, :bar).should be_true + expect(@controller.current_ability).to be_kind_of(Ability) + expect(@controller.can?(:foo, :bar)).to be_false + expect(@controller.cannot?(:foo, :bar)).to be_true end it "load_and_authorize_resource should setup a before filter which passes call to ControllerResource" do - stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.load_and_authorize_resource - mock(@controller_class).before_filter({}) { |options, block| block.call(@controller) } + expect(cancan_resource_class = double).to receive(:load_and_authorize_resource) + allow(CanCan::ControllerResource).to receive(:new).with(@controller, nil, :foo => :bar) {cancan_resource_class } + expect(@controller_class).to receive(:before_filter).with({}) { |options, &block| block.call(@controller) } @controller_class.load_and_authorize_resource :foo => :bar end it "load_and_authorize_resource should properly pass first argument as the resource name" do - stub(CanCan::ControllerResource).new(@controller, :project, :foo => :bar).mock!.load_and_authorize_resource - mock(@controller_class).before_filter({}) { |options, block| block.call(@controller) } + expect(cancan_resource_class = double).to receive(:load_and_authorize_resource) + allow(CanCan::ControllerResource).to receive(:new).with(@controller, :project, :foo => :bar) {cancan_resource_class} + expect(@controller_class).to receive(:before_filter).with({}) { |options, &block| block.call(@controller) } @controller_class.load_and_authorize_resource :project, :foo => :bar end it "load_and_authorize_resource with :prepend should prepend the before filter" do - mock(@controller_class).prepend_before_filter({}) + expect(@controller_class).to receive(:prepend_before_filter).with({}) @controller_class.load_and_authorize_resource :foo => :bar, :prepend => true end it "authorize_resource should setup a before filter which passes call to ControllerResource" do - stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.authorize_resource - mock(@controller_class).before_filter(:except => :show, :if => true) { |options, block| block.call(@controller) } + expect(cancan_resource_class = double).to receive(:authorize_resource) + allow(CanCan::ControllerResource).to receive(:new).with(@controller, nil, :foo => :bar) {cancan_resource_class} + expect(@controller_class).to receive(:before_filter).with(:except => :show, :if => true) { |options, &block| block.call(@controller) } @controller_class.authorize_resource :foo => :bar, :except => :show, :if => true end it "load_resource should setup a before filter which passes call to ControllerResource" do - stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.load_resource - mock(@controller_class).before_filter(:only => [:show, :index], :unless => false) { |options, block| block.call(@controller) } + expect(cancan_resource_class = double).to receive(:load_resource) + allow(CanCan::ControllerResource).to receive(:new).with(@controller, nil, :foo => :bar) {cancan_resource_class} + expect(@controller_class).to receive(:before_filter).with(:only => [:show, :index], :unless => false) { |options, &block| block.call(@controller) } @controller_class.load_resource :foo => :bar, :only => [:show, :index], :unless => false end it "skip_authorization_check should set up a before filter which sets @_authorized to true" do - mock(@controller_class).before_filter(:filter_options) { |options, block| block.call(@controller) } + expect(@controller_class).to receive(:before_filter).with(:filter_options) { |options, &block| block.call(@controller) } @controller_class.skip_authorization_check(:filter_options) - @controller.instance_variable_get(:@_authorized).should be_true + expect(@controller.instance_variable_get(:@_authorized)).to be_true end it "check_authorization should trigger AuthorizationNotPerformed in after filter" do - mock(@controller_class).after_filter(:only => [:test]) { |options, block| block.call(@controller) } - lambda { + expect(@controller_class).to receive(:after_filter).with(:only => [:test]) { |options, &block| block.call(@controller) } + expect { @controller_class.check_authorization(:only => [:test]) - }.should raise_error(CanCan::AuthorizationNotPerformed) + }.to raise_error(CanCan::AuthorizationNotPerformed) end it "check_authorization should not trigger AuthorizationNotPerformed when :if is false" do - stub(@controller).check_auth? { false } - mock(@controller_class).after_filter({}) { |options, block| block.call(@controller) } - lambda { + allow(@controller).to receive(:check_auth?) { false } + allow(@controller_class).to receive(:after_filter).with({}) { |options, &block| block.call(@controller) } + expect { @controller_class.check_authorization(:if => :check_auth?) - }.should_not raise_error(CanCan::AuthorizationNotPerformed) + }.not_to raise_error end it "check_authorization should not trigger AuthorizationNotPerformed when :unless is true" do - stub(@controller).engine_controller? { true } - mock(@controller_class).after_filter({}) { |options, block| block.call(@controller) } - lambda { + allow(@controller).to receive(:engine_controller?) { true } + expect(@controller_class).to receive(:after_filter).with({}) { |options, &block| block.call(@controller) } + expect { @controller_class.check_authorization(:unless => :engine_controller?) - }.should_not raise_error(CanCan::AuthorizationNotPerformed) + }.not_to raise_error end it "check_authorization should not raise error when @_authorized is set" do @controller.instance_variable_set(:@_authorized, true) - mock(@controller_class).after_filter(:only => [:test]) { |options, block| block.call(@controller) } - lambda { + expect(@controller_class).to receive(:after_filter).with(:only => [:test]) { |options, &block| block.call(@controller) } + expect { @controller_class.check_authorization(:only => [:test]) - }.should_not raise_error(CanCan::AuthorizationNotPerformed) + }.not_to raise_error end it "cancan_resource_class should be ControllerResource by default" do - @controller.class.cancan_resource_class.should == CanCan::ControllerResource + expect(@controller.class.cancan_resource_class).to eq(CanCan::ControllerResource) end it "cancan_resource_class should be InheritedResource when class includes InheritedResources::Actions" do - stub(@controller.class).ancestors { ["InheritedResources::Actions"] } - @controller.class.cancan_resource_class.should == CanCan::InheritedResource + allow(@controller.class).to receive(:ancestors) { ["InheritedResources::Actions"] } + expect(@controller.class.cancan_resource_class).to eq(CanCan::InheritedResource) end it "cancan_skipper should be an empty hash with :authorize and :load options and remember changes" do - @controller_class.cancan_skipper.should == {:authorize => {}, :load => {}} + expect(@controller_class.cancan_skipper).to eq({:authorize => {}, :load => {}}) @controller_class.cancan_skipper[:load] = true - @controller_class.cancan_skipper[:load].should == true + expect(@controller_class.cancan_skipper[:load]).to be_true end it "skip_authorize_resource should add itself to the cancan skipper with given model name and options" do @controller_class.skip_authorize_resource(:project, :only => [:index, :show]) - @controller_class.cancan_skipper[:authorize][:project].should == {:only => [:index, :show]} + expect(@controller_class.cancan_skipper[:authorize][:project]).to eq({:only => [:index, :show]}) @controller_class.skip_authorize_resource(:only => [:index, :show]) - @controller_class.cancan_skipper[:authorize][nil].should == {:only => [:index, :show]} + expect(@controller_class.cancan_skipper[:authorize][nil]).to eq({:only => [:index, :show]}) @controller_class.skip_authorize_resource(:article) - @controller_class.cancan_skipper[:authorize][:article].should == {} + expect(@controller_class.cancan_skipper[:authorize][:article]).to eq({}) end it "skip_load_resource should add itself to the cancan skipper with given model name and options" do @controller_class.skip_load_resource(:project, :only => [:index, :show]) - @controller_class.cancan_skipper[:load][:project].should == {:only => [:index, :show]} + expect(@controller_class.cancan_skipper[:load][:project]).to eq({:only => [:index, :show]}) @controller_class.skip_load_resource(:only => [:index, :show]) - @controller_class.cancan_skipper[:load][nil].should == {:only => [:index, :show]} + expect(@controller_class.cancan_skipper[:load][nil]).to eq({:only => [:index, :show]}) @controller_class.skip_load_resource(:article) - @controller_class.cancan_skipper[:load][:article].should == {} + expect(@controller_class.cancan_skipper[:load][:article]).to eq({}) end it "skip_load_and_authore_resource should add itself to the cancan skipper with given model name and options" do @controller_class.skip_load_and_authorize_resource(:project, :only => [:index, :show]) - @controller_class.cancan_skipper[:load][:project].should == {:only => [:index, :show]} - @controller_class.cancan_skipper[:authorize][:project].should == {:only => [:index, :show]} + expect(@controller_class.cancan_skipper[:load][:project]).to eq({:only => [:index, :show]}) + expect(@controller_class.cancan_skipper[:authorize][:project]).to eq({:only => [:index, :show]}) end end diff --git a/spec/cancan/controller_resource_spec.rb b/spec/cancan/controller_resource_spec.rb index b04c661c..103a2a8e 100644 --- a/spec/cancan/controller_resource_spec.rb +++ b/spec/cancan/controller_resource_spec.rb @@ -6,9 +6,9 @@ @controller_class = Class.new @controller = @controller_class.new @ability = Ability.new(nil) - stub(@controller).params { @params } - stub(@controller).current_ability { @ability } - stub(@controller_class).cancan_skipper { {:authorize => {}, :load => {}} } + allow(@controller).to receive(:params) { @params } + allow(@controller).to receive(:current_ability) { @ability } + allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {}, :load => {}} } end it "should load the resource into an instance variable if params[:id] is specified" do @@ -16,7 +16,7 @@ @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "should not load resource into an instance variable if already set" do @@ -24,7 +24,7 @@ @controller.instance_variable_set(:@project, :some_project) resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).should == :some_project + expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end it "should properly load resource for namespaced controller" do @@ -32,7 +32,7 @@ @params.merge!(:controller => "admin/projects", :action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "should attempt to load a resource with the same namespace as the controller when using :: for namespace" do @@ -44,7 +44,7 @@ class Project < ::Project; end @params.merge!(:controller => "MyEngine::ProjectsController", :action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end # Rails includes namespace in params, see issue #349 @@ -56,7 +56,7 @@ class Project < ::Project; end @params.merge!(:controller => "MyEngine::ProjectsController", :action => "create", :my_engine_project => {:name => "foobar"}) resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).name.should == "foobar" + expect(@controller.instance_variable_get(:@project).name).to eq("foobar") end it "should properly load resource for namespaced controller when using '::' for namespace" do @@ -64,7 +64,7 @@ class Project < ::Project; end @params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "has the specified nested resource_class when using / for namespace" do @@ -74,28 +74,28 @@ class Dashboard; end @ability.can(:index, "admin/dashboard") @params.merge!(:controller => "admin/dashboard", :action => "index") resource = CanCan::ControllerResource.new(@controller, :authorize => true) - resource.send(:resource_class).should == Admin::Dashboard + expect(resource.send(:resource_class)).to eq(Admin::Dashboard) end it "should build a new resource with hash if params[:id] is not specified" do @params.merge!(:action => "create", :project => {:name => "foobar"}) resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).name.should == "foobar" + expect(@controller.instance_variable_get(:@project).name).to eq("foobar") end it "should build a new resource for namespaced model with hash if params[:id] is not specified" do @params.merge!(:action => "create", 'sub_project' => {:name => "foobar"}) resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project) resource.load_resource - @controller.instance_variable_get(:@project).name.should == "foobar" + expect(@controller.instance_variable_get(:@project).name).to eq("foobar") end it "should build a new resource for namespaced controller and namespaced model with hash if params[:id] is not specified" do @params.merge!(:controller => "Admin::SubProjectsController", :action => "create", 'sub_project' => {:name => "foobar"}) resource = CanCan::ControllerResource.new(@controller, :class => Project) resource.load_resource - @controller.instance_variable_get(:@sub_project).name.should == "foobar" + expect(@controller.instance_variable_get(:@sub_project).name).to eq("foobar") end it "should build a new resource with attributes from current ability" do @@ -103,7 +103,7 @@ class Dashboard; end @ability.can(:create, Project, :name => "from conditions") resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).name.should == "from conditions" + expect(@controller.instance_variable_get(:@project).name).to eq("from conditions") end it "should override initial attributes with params" do @@ -111,72 +111,72 @@ class Dashboard; end @ability.can(:create, Project, :name => "from conditions") resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).name.should == "from params" + expect(@controller.instance_variable_get(:@project).name).to eq("from params") end it "should build a collection when on index action when class responds to accessible_by" do - stub(Project).accessible_by(@ability, :index) { :found_projects } + allow(Project).to receive(:accessible_by).with(@ability, :index) { :found_projects } @params[:action] = "index" resource = CanCan::ControllerResource.new(@controller, :project) resource.load_resource - @controller.instance_variable_get(:@project).should be_nil - @controller.instance_variable_get(:@projects).should == :found_projects + expect(@controller.instance_variable_get(:@project)).to be_nil + expect(@controller.instance_variable_get(:@projects)).to eq(:found_projects) end it "should not build a collection when on index action when class does not respond to accessible_by" do @params[:action] = "index" resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).should be_nil - @controller.instance_variable_defined?(:@projects).should be_false + expect(@controller.instance_variable_get(:@project)).to be_nil + expect(@controller.instance_variable_defined?(:@projects)).to be_false end it "should not use accessible_by when defining abilities through a block" do - stub(Project).accessible_by(@ability) { :found_projects } + allow(Project).to receive(:accessible_by).with(@ability) { :found_projects } @params[:action] = "index" @ability.can(:read, Project) { |p| false } resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).should be_nil - @controller.instance_variable_defined?(:@projects).should be_false + expect(@controller.instance_variable_get(:@project)).to be_nil + expect(@controller.instance_variable_defined?(:@projects)).to be_false end it "should not authorize single resource in collection action" do @params[:action] = "index" @controller.instance_variable_set(:@project, :some_project) - stub(@controller).authorize!(:index, Project) { raise CanCan::AccessDenied } + allow(@controller).to receive(:authorize!).with(:index, Project) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller) - lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied) + expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end it "should authorize parent resource in collection action" do @params[:action] = "index" @controller.instance_variable_set(:@category, :some_category) - stub(@controller).authorize!(:show, :some_category) { raise CanCan::AccessDenied } + allow(@controller).to receive(:authorize!).with(:show, :some_category) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller, :category, :parent => true) - lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied) + expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end it "should perform authorization using controller action and loaded model" do @params.merge!(:action => "show", :id => "123") @controller.instance_variable_set(:@project, :some_project) - stub(@controller).authorize!(:show, :some_project) { raise CanCan::AccessDenied } + allow(@controller).to receive(:authorize!).with(:show, :some_project) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller) - lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied) + expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end it "should perform authorization using controller action and non loaded model" do @params.merge!(:action => "show", :id => "123") - stub(@controller).authorize!(:show, Project) { raise CanCan::AccessDenied } + allow(@controller).to receive(:authorize!).with(:show, Project) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller) - lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied) + expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end it "should call load_resource and authorize_resource for load_and_authorize_resource" do @params.merge!(:action => "show", :id => "123") resource = CanCan::ControllerResource.new(@controller) - mock(resource).load_resource - mock(resource).authorize_resource + expect(resource).to receive(:load_resource) + expect(resource).to receive(:authorize_resource) resource.load_and_authorize_resource end @@ -184,51 +184,51 @@ class Dashboard; end @params.merge!(:action => "sort", :id => "123") resource = CanCan::ControllerResource.new(@controller, :collection => [:sort, :list]) resource.load_resource - @controller.instance_variable_get(:@project).should be_nil + expect(@controller.instance_variable_get(:@project)).to be_nil end it "should load a collection resource when on custom action with no id param" do - stub(Project).accessible_by(@ability, :sort) { :found_projects } + allow(Project).to receive(:accessible_by).with(@ability, :sort) { :found_projects } @params[:action] = "sort" resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).should be_nil - @controller.instance_variable_get(:@projects).should == :found_projects + expect(@controller.instance_variable_get(:@project)).to be_nil + expect(@controller.instance_variable_get(:@projects)).to eq(:found_projects) end it "should build a resource when on custom new action even when params[:id] exists" do @params.merge!(:action => "build", :id => "123") - stub(Project).new { :some_project } + allow(Project).to receive(:new) { :some_project } resource = CanCan::ControllerResource.new(@controller, :new => :build) resource.load_resource - @controller.instance_variable_get(:@project).should == :some_project + expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end it "should not try to load resource for other action if params[:id] is undefined" do @params[:action] = "list" resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).should be_nil + expect(@controller.instance_variable_get(:@project)).to be_nil end it "should be a parent resource when name is provided which doesn't match controller" do resource = CanCan::ControllerResource.new(@controller, :category) - resource.should be_parent + expect(resource).to be_parent end it "should not be a parent resource when name is provided which matches controller" do resource = CanCan::ControllerResource.new(@controller, :project) - resource.should_not be_parent + expect(resource).to_not be_parent end it "should be parent if specified in options" do resource = CanCan::ControllerResource.new(@controller, :project, {:parent => true}) - resource.should be_parent + expect(resource).to be_parent end it "should not be parent if specified in options" do resource = CanCan::ControllerResource.new(@controller, :category, {:parent => false}) - resource.should_not be_parent + expect(resource).to_not be_parent end it "should have the specified resource_class if 'name' is passed to load_resource" do @@ -236,7 +236,7 @@ class Section end resource = CanCan::ControllerResource.new(@controller, :section) - resource.send(:resource_class).should == Section + expect(resource.send(:resource_class)).to eq(Section) end it "should load parent resource through proper id parameter" do @@ -244,37 +244,37 @@ class Section @params.merge!(:controller => "categories", :action => "index", :project_id => project.id) resource = CanCan::ControllerResource.new(@controller, :project) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "should load resource through the association of another parent resource using instance variable" do @params.merge!(:action => "show", :id => "123") - category = Object.new + category = double(projects: {}) @controller.instance_variable_set(:@category, category) - stub(category).projects.stub!.find("123") { :some_project } + allow(category.projects).to receive(:find).with("123") { :some_project } resource = CanCan::ControllerResource.new(@controller, :through => :category) resource.load_resource - @controller.instance_variable_get(:@project).should == :some_project + expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end it "should load resource through the custom association name" do @params.merge!(:action => "show", :id => "123") - category = Object.new + category = double(custom_projects: {}) @controller.instance_variable_set(:@category, category) - stub(category).custom_projects.stub!.find("123") { :some_project } + allow(category.custom_projects).to receive(:find).with("123") { :some_project } resource = CanCan::ControllerResource.new(@controller, :through => :category, :through_association => :custom_projects) resource.load_resource - @controller.instance_variable_get(:@project).should == :some_project + expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end it "should load resource through the association of another parent resource using method" do @params.merge!(:action => "show", :id => "123") - category = Object.new - stub(@controller).category { category } - stub(category).projects.stub!.find("123") { :some_project } + category = double(projects: {}) + allow(@controller).to receive(:category) { category } + allow(category.projects).to receive(:find).with("123") { :some_project } resource = CanCan::ControllerResource.new(@controller, :through => :category) resource.load_resource - @controller.instance_variable_get(:@project).should == :some_project + expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end it "should not load through parent resource if instance isn't loaded when shallow" do @@ -282,49 +282,47 @@ class Section @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :through => :category, :shallow => true) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "should raise AccessDenied when attempting to load resource through nil" do project = Project.create! @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :through => :category) - lambda { + expect { resource.load_resource - }.should raise_error(CanCan::AccessDenied) { |exception| - exception.action.should == :show - exception.subject.should == Project + }.to raise_error(CanCan::AccessDenied) { |exception| + expect(exception.action).to eq(:show) + expect(exception.subject).to eq(Project) } - @controller.instance_variable_get(:@project).should be_nil + expect(@controller.instance_variable_get(:@project)).to be_nil end it "should authorize nested resource through parent association on index action" do @params.merge!(:action => "index") - category = Object.new - @controller.instance_variable_set(:@category, category) - stub(@controller).authorize!(:index, category => Project) { raise CanCan::AccessDenied } + @controller.instance_variable_set(:@category, category = double) + allow(@controller).to receive(:authorize!).with(:index, category => Project) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller, :through => :category) - lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied) + expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end it "should load through first matching if multiple are given" do @params.merge!(:action => "show", :id => "123") - category = Object.new + category = double(projects: {}) @controller.instance_variable_set(:@category, category) - stub(category).projects.stub!.find("123") { :some_project } + allow(category.projects).to receive(:find).with("123") { :some_project } resource = CanCan::ControllerResource.new(@controller, :through => [:category, :user]) resource.load_resource - @controller.instance_variable_get(:@project).should == :some_project + expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end it "should find record through has_one association with :singleton option without id param" do @params.merge!(:action => "show", :id => nil) - category = Object.new + category = double(project: :some_project) @controller.instance_variable_set(:@category, category) - stub(category).project { :some_project } resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true) resource.load_resource - @controller.instance_variable_get(:@project).should == :some_project + expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end it "should not build record through has_one association with :singleton option because it can cause it to delete it in the database" do @@ -333,8 +331,8 @@ class Section @controller.instance_variable_set(:@category, category) resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true) resource.load_resource - @controller.instance_variable_get(:@project).name.should == "foobar" - @controller.instance_variable_get(:@project).category.should == category + expect(@controller.instance_variable_get(:@project).name).to eq("foobar") + expect(@controller.instance_variable_get(:@project).category).to eq(category) end it "should find record through has_one association with :singleton and :shallow options" do @@ -342,22 +340,22 @@ class Section @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true, :shallow => true) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "should build record through has_one association with :singleton and :shallow options" do @params.merge!(:action => "create", :project => {:name => "foobar"}) resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true, :shallow => true) resource.load_resource - @controller.instance_variable_get(:@project).name.should == "foobar" + expect(@controller.instance_variable_get(:@project).name).to eq("foobar") end it "should only authorize :show action on parent resource" do project = Project.create! @params.merge!(:action => "new", :project_id => project.id) - stub(@controller).authorize!(:show, project) { raise CanCan::AccessDenied } + allow(@controller).to receive(:authorize!).with(:show, project) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller, :project, :parent => true) - lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied) + expect { resource.load_and_authorize_resource }.to raise_error(CanCan::AccessDenied) end it "should load the model using a custom class" do @@ -365,7 +363,7 @@ class Section @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :class => Project) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "should load the model using a custom namespaced class" do @@ -373,23 +371,23 @@ class Section @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "should authorize based on resource name if class is false" do @params.merge!(:action => "show", :id => "123") - stub(@controller).authorize!(:show, :project) { raise CanCan::AccessDenied } + allow(@controller).to receive(:authorize!).with(:show, :project) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller, :class => false) - lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied) + expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end it "should load and authorize using custom instance name" do project = Project.create! @params.merge!(:action => "show", :id => project.id) - stub(@controller).authorize!(:show, project) { raise CanCan::AccessDenied } + allow(@controller).to receive(:authorize!).with(:show, project) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller, :instance_name => :custom_project) - lambda { resource.load_and_authorize_resource }.should raise_error(CanCan::AccessDenied) - @controller.instance_variable_get(:@custom_project).should == project + expect { resource.load_and_authorize_resource }.to raise_error(CanCan::AccessDenied) + expect(@controller.instance_variable_get(:@custom_project)).to eq(project) end it "should load resource using custom ID param" do @@ -397,14 +395,14 @@ class Section @params.merge!(:action => "show", :the_project => project.id) resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end # CVE-2012-5664 it "should always convert id param to string" do @params.merge!(:action => "show", :the_project => { :malicious => "I am" }) resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project) - resource.send(:id_param).class.should == String + expect(resource.send(:id_param).class).to eq(String) end it "should id param return nil if param is nil" do @@ -418,7 +416,7 @@ class Section @params.merge!(:action => "show", :id => "foo") resource = CanCan::ControllerResource.new(@controller, :find_by => :name) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "should allow full find method to be passed into find_by option" do @@ -426,72 +424,72 @@ class Section @params.merge!(:action => "show", :id => "foo") resource = CanCan::ControllerResource.new(@controller, :find_by => :find_by_name) resource.load_resource - @controller.instance_variable_get(:@project).should == project + expect(@controller.instance_variable_get(:@project)).to eq(project) end it "should raise ImplementationRemoved when adding :name option" do - lambda { + expect { CanCan::ControllerResource.new(@controller, :name => :foo) - }.should raise_error(CanCan::ImplementationRemoved) + }.to raise_error(CanCan::ImplementationRemoved) end it "should raise ImplementationRemoved exception when specifying :resource option since it is no longer used" do - lambda { + expect { CanCan::ControllerResource.new(@controller, :resource => Project) - }.should raise_error(CanCan::ImplementationRemoved) + }.to raise_error(CanCan::ImplementationRemoved) end it "should raise ImplementationRemoved exception when passing :nested option" do - lambda { + expect { CanCan::ControllerResource.new(@controller, :nested => :project) - }.should raise_error(CanCan::ImplementationRemoved) + }.to raise_error(CanCan::ImplementationRemoved) end it "should skip resource behavior for :only actions in array" do - stub(@controller_class).cancan_skipper { {:load => {nil => {:only => [:index, :show]}}} } + allow(@controller_class).to receive(:cancan_skipper) { {:load => {nil => {:only => [:index, :show]}}} } @params.merge!(:action => "index") - CanCan::ControllerResource.new(@controller).skip?(:load).should be_true - CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load).should be_false + expect(CanCan::ControllerResource.new(@controller).skip?(:load)).to be_true + expect(CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load)).to be_false @params.merge!(:action => "show") - CanCan::ControllerResource.new(@controller).skip?(:load).should be_true + expect(CanCan::ControllerResource.new(@controller).skip?(:load)).to be_true @params.merge!(:action => "other_action") - CanCan::ControllerResource.new(@controller).skip?(:load).should be_false + expect(CanCan::ControllerResource.new(@controller).skip?(:load)).to be_false end it "should skip resource behavior for :only one action on resource" do - stub(@controller_class).cancan_skipper { {:authorize => {:project => {:only => :index}}} } + allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {:project => {:only => :index}}} } @params.merge!(:action => "index") - CanCan::ControllerResource.new(@controller).skip?(:authorize).should be_false - CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_true + expect(CanCan::ControllerResource.new(@controller).skip?(:authorize)).to be_false + expect(CanCan::ControllerResource.new(@controller, :project).skip?(:authorize)).to be_true @params.merge!(:action => "other_action") - CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_false + expect(CanCan::ControllerResource.new(@controller, :project).skip?(:authorize)).to be_false end it "should skip resource behavior :except actions in array" do - stub(@controller_class).cancan_skipper { {:load => {nil => {:except => [:index, :show]}}} } + allow(@controller_class).to receive(:cancan_skipper) { {:load => {nil => {:except => [:index, :show]}}} } @params.merge!(:action => "index") - CanCan::ControllerResource.new(@controller).skip?(:load).should be_false + expect(CanCan::ControllerResource.new(@controller).skip?(:load)).to be_false @params.merge!(:action => "show") - CanCan::ControllerResource.new(@controller).skip?(:load).should be_false + expect(CanCan::ControllerResource.new(@controller).skip?(:load)).to be_false @params.merge!(:action => "other_action") - CanCan::ControllerResource.new(@controller).skip?(:load).should be_true - CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load).should be_false + expect(CanCan::ControllerResource.new(@controller).skip?(:load)).to be_true + expect(CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load)).to be_false end it "should skip resource behavior :except one action on resource" do - stub(@controller_class).cancan_skipper { {:authorize => {:project => {:except => :index}}} } + allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {:project => {:except => :index}}} } @params.merge!(:action => "index") - CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_false + expect(CanCan::ControllerResource.new(@controller, :project).skip?(:authorize)).to be_false @params.merge!(:action => "other_action") - CanCan::ControllerResource.new(@controller).skip?(:authorize).should be_false - CanCan::ControllerResource.new(@controller, :project).skip?(:authorize).should be_true + expect(CanCan::ControllerResource.new(@controller).skip?(:authorize)).to be_false + expect(CanCan::ControllerResource.new(@controller, :project).skip?(:authorize)).to be_true end it "should skip loading and authorization" do - stub(@controller_class).cancan_skipper { {:authorize => {nil => {}}, :load => {nil => {}}} } + allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {nil => {}}, :load => {nil => {}}} } @params.merge!(:action => "new") resource = CanCan::ControllerResource.new(@controller) - lambda { resource.load_and_authorize_resource }.should_not raise_error - @controller.instance_variable_get(:@project).should be_nil + expect { resource.load_and_authorize_resource }.not_to raise_error + expect(@controller.instance_variable_get(:@project)).to be_nil end end diff --git a/spec/cancan/exceptions_spec.rb b/spec/cancan/exceptions_spec.rb index 58e65b78..e3daa4f3 100644 --- a/spec/cancan/exceptions_spec.rb +++ b/spec/cancan/exceptions_spec.rb @@ -7,14 +7,14 @@ end it "should have action and subject accessors" do - @exception.action.should == :some_action - @exception.subject.should == :some_subject + expect(@exception.action).to eq(:some_action) + expect(@exception.subject).to eq(:some_subject) end it "should have a changable default message" do - @exception.message.should == "You are not authorized to access this page." + expect(@exception.message).to eq("You are not authorized to access this page.") @exception.default_message = "Unauthorized!" - @exception.message.should == "Unauthorized!" + expect(@exception.message).to eq("Unauthorized!") end end @@ -24,12 +24,12 @@ end it "should have nil action and subject" do - @exception.action.should be_nil - @exception.subject.should be_nil + expect(@exception.action).to be_nil + expect(@exception.subject).to be_nil end it "should have passed message" do - @exception.message.should == "Access denied!" + expect(@exception.message).to eq("Access denied!") end end @@ -41,18 +41,18 @@ it "uses i18n for the default message" do I18n.backend.store_translations :en, :unauthorized => {:default => "This is a different message"} @exception = CanCan::AccessDenied.new - @exception.message.should == "This is a different message" + expect(@exception.message).to eq("This is a different message") end it "defaults to a nice message" do @exception = CanCan::AccessDenied.new - @exception.message.should == "You are not authorized to access this page." + expect(@exception.message).to eq("You are not authorized to access this page.") end it "does not use translation if a message is given" do @exception = CanCan::AccessDenied.new("Hey! You're not welcome here") - @exception.message.should == "Hey! You're not welcome here" - @exception.message.should_not == "You are not authorized to access this page." + expect(@exception.message).to eq("Hey! You're not welcome here") + expect(@exception.message).to_not eq("You are not authorized to access this page.") end end end diff --git a/spec/cancan/inherited_resource_spec.rb b/spec/cancan/inherited_resource_spec.rb index 3779fe6f..94b8d008 100644 --- a/spec/cancan/inherited_resource_spec.rb +++ b/spec/cancan/inherited_resource_spec.rb @@ -6,55 +6,55 @@ @controller_class = Class.new @controller = @controller_class.new @ability = Ability.new(nil) - stub(@controller).params { @params } - stub(@controller).current_ability { @ability } - stub(@controller_class).cancan_skipper { {:authorize => {}, :load => {}} } + allow(@controller).to receive(:params).and_return { @params } + allow(@controller).to receive(:current_ability) { @ability } + allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {}, :load => {}} } end it "show should load resource through @controller.resource" do @params.merge!(:action => "show", :id => 123) - stub(@controller).resource { :project_resource } + allow(@controller).to receive(:resource) { :project_resource } CanCan::InheritedResource.new(@controller).load_resource - @controller.instance_variable_get(:@project).should == :project_resource + expect(@controller.instance_variable_get(:@project)).to eq(:project_resource) end it "new should load through @controller.build_resource" do @params[:action] = "new" - stub(@controller).build_resource { :project_resource } + allow(@controller).to receive(:build_resource) { :project_resource } CanCan::InheritedResource.new(@controller).load_resource - @controller.instance_variable_get(:@project).should == :project_resource + expect(@controller.instance_variable_get(:@project)).to eq(:project_resource) end it "index should load through @controller.association_chain when parent" do @params[:action] = "index" - stub(@controller).association_chain { @controller.instance_variable_set(:@project, :project_resource) } + allow(@controller).to receive(:association_chain) { @controller.instance_variable_set(:@project, :project_resource) } CanCan::InheritedResource.new(@controller, :parent => true).load_resource - @controller.instance_variable_get(:@project).should == :project_resource + expect(@controller.instance_variable_get(:@project)).to eq(:project_resource) end it "index should load through @controller.end_of_association_chain" do @params[:action] = "index" - stub(Project).accessible_by(@ability, :index) { :projects } - stub(@controller).end_of_association_chain { Project } + allow(Project).to receive(:accessible_by).with(@ability, :index) { :projects } + allow(@controller).to receive(:end_of_association_chain) { Project } CanCan::InheritedResource.new(@controller).load_resource - @controller.instance_variable_get(:@projects).should == :projects + expect(@controller.instance_variable_get(:@projects)).to eq(:projects) end it "should build a new resource with attributes from current ability" do @params[:action] = "new" @ability.can(:create, Project, :name => "from conditions") - stub(@controller).build_resource { Struct.new(:name).new } + allow(@controller).to receive(:build_resource) { Struct.new(:name).new } resource = CanCan::InheritedResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).name.should == "from conditions" + expect(@controller.instance_variable_get(:@project).name).to eq("from conditions") end it "should override initial attributes with params" do @params.merge!(:action => "new", :project => {:name => "from params"}) @ability.can(:create, Project, :name => "from conditions") - stub(@controller).build_resource { Struct.new(:name).new } + allow(@controller).to receive(:build_resource) { Struct.new(:name).new } resource = CanCan::ControllerResource.new(@controller) resource.load_resource - @controller.instance_variable_get(:@project).name.should == "from params" + expect(@controller.instance_variable_get(:@project).name).to eq("from params") end end diff --git a/spec/cancan/matchers_spec.rb b/spec/cancan/matchers_spec.rb index de6a439e..e9c594e8 100644 --- a/spec/cancan/matchers_spec.rb +++ b/spec/cancan/matchers_spec.rb @@ -2,32 +2,28 @@ describe "be_able_to" do it "delegates to can?" do - object = Object.new - mock(object).can?(:read, 123) { true } - object.should be_able_to(:read, 123) + expect(object = double).to receive(:can?).with(:read, 123) { true } + expect(object).to be_able_to(:read, 123) end it "reports a nice failure message for should" do - object = Object.new - mock(object).can?(:read, 123) { false } - expect do - object.should be_able_to(:read, 123) - end.should raise_error('expected to be able to :read 123') + expect(object = double).to receive(:can?).with(:read, 123) { false } + expect { + expect(object).to be_able_to(:read, 123) + }.to raise_error('expected to be able to :read 123') end it "reports a nice failure message for should not" do - object = Object.new - mock(object).can?(:read, 123) { true } - expect do - object.should_not be_able_to(:read, 123) - end.should raise_error('expected not to be able to :read 123') + expect(object = double).to receive(:can?).with(:read, 123) { true } + expect { + expect(object).to_not be_able_to(:read, 123) + }.to raise_error('expected not to be able to :read 123') end it "delegates additional arguments to can? and reports in failure message" do - object = Object.new - mock(object).can?(:read, 123, 456) { false } - expect do - object.should be_able_to(:read, 123, 456) - end.should raise_error('expected to be able to :read 123 456') + expect(object = double).to receive(:can?).with(:read, 123, 456) { false } + expect { + expect(object).to be_able_to(:read, 123, 456) + }.to raise_error('expected to be able to :read 123 456') end end diff --git a/spec/cancan/model_adapters/active_record_adapter_spec.rb b/spec/cancan/model_adapters/active_record_adapter_spec.rb index 27c7d99f..1831a095 100644 --- a/spec/cancan/model_adapters/active_record_adapter_spec.rb +++ b/spec/cancan/model_adapters/active_record_adapter_spec.rb @@ -52,39 +52,38 @@ before(:each) do Article.delete_all Comment.delete_all - @ability = Object.new - @ability.extend(CanCan::Ability) + (@ability = double).extend(CanCan::Ability) @article_table = Article.table_name @comment_table = Comment.table_name end it "should be for only active record classes" do - CanCan::ModelAdapters::ActiveRecordAdapter.should_not be_for_class(Object) - CanCan::ModelAdapters::ActiveRecordAdapter.should be_for_class(Article) - CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::ActiveRecordAdapter + expect(CanCan::ModelAdapters::ActiveRecordAdapter).to_not be_for_class(Object) + expect(CanCan::ModelAdapters::ActiveRecordAdapter).to be_for_class(Article) + expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)).to eq(CanCan::ModelAdapters::ActiveRecordAdapter) end it "should find record" do article = Article.create! - CanCan::ModelAdapters::ActiveRecordAdapter.find(Article, article.id).should == article + expect(CanCan::ModelAdapters::ActiveRecordAdapter.find(Article, article.id)).to eq(article) end it "should not fetch any records when no abilities are defined" do Article.create! - Article.accessible_by(@ability).should be_empty + expect(Article.accessible_by(@ability)).to be_empty end it "should fetch all articles when one can read all" do @ability.can :read, Article article = Article.create! - Article.accessible_by(@ability).should == [article] + expect(Article.accessible_by(@ability)).to eq([article]) end it "should fetch only the articles that are published" do @ability.can :read, Article, :published => true article1 = Article.create!(:published => true) article2 = Article.create!(:published => false) - Article.accessible_by(@ability).should == [article1] + expect(Article.accessible_by(@ability)).to eq([article1]) end it "should fetch any articles which are published or secret" do @@ -94,7 +93,7 @@ article2 = Article.create!(:published => true, :secret => true) article3 = Article.create!(:published => false, :secret => true) article4 = Article.create!(:published => false, :secret => false) - Article.accessible_by(@ability).should == [article1, article2, article3] + expect(Article.accessible_by(@ability)).to eq([article1, article2, article3]) end it "should fetch only the articles that are published and not secret" do @@ -104,14 +103,14 @@ article2 = Article.create!(:published => true, :secret => true) article3 = Article.create!(:published => false, :secret => true) article4 = Article.create!(:published => false, :secret => false) - Article.accessible_by(@ability).should == [article1] + expect(Article.accessible_by(@ability)).to eq([article1]) end it "should only read comments for articles which are published" do @ability.can :read, Comment, :article => { :published => true } comment1 = Comment.create!(:article => Article.create!(:published => true)) comment2 = Comment.create!(:article => Article.create!(:published => false)) - Comment.accessible_by(@ability).should == [comment1] + expect(Comment.accessible_by(@ability)).to eq([comment1]) end it "should only read articles which are published or in visible categories" do @@ -136,7 +135,7 @@ @ability.can :read, Comment, :article => { :category => { :visible => true } } comment1 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => true))) comment2 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => false))) - Comment.accessible_by(@ability).should == [comment1] + expect(Comment.accessible_by(@ability)).to eq([comment1]) end it "should allow conditions in SQL and merge with hash conditions" do @@ -146,14 +145,14 @@ article2 = Article.create!(:published => true, :secret => true) article3 = Article.create!(:published => false, :secret => true) article4 = Article.create!(:published => false, :secret => false) - Article.accessible_by(@ability).should == [article1, article2, article3] + expect(Article.accessible_by(@ability)).to eq([article1, article2, article3]) end it "should allow a scope for conditions" do @ability.can :read, Article, Article.where(:secret => true) article1 = Article.create!(:secret => true) article2 = Article.create!(:secret => false) - Article.accessible_by(@ability).should == [article1] + expect(Article.accessible_by(@ability)).to eq([article1]) end it "should fetch only associated records when using with a scope for conditions" do @@ -162,20 +161,20 @@ category2 = Category.create!(:visible => true) article1 = Article.create!(:secret => true, :category => category1) article2 = Article.create!(:secret => true, :category => category2) - category1.articles.accessible_by(@ability).should == [article1] + expect(category1.articles.accessible_by(@ability)).to eq([article1]) end it "should raise an exception when trying to merge scope with other conditions" do @ability.can :read, Article, :published => true @ability.can :read, Article, Article.where(:secret => true) - lambda { Article.accessible_by(@ability) }.should raise_error(CanCan::Error, "Unable to merge an Active Record scope with other conditions. Instead use a hash or SQL for read Article ability.") + expect(lambda { Article.accessible_by(@ability) }).to raise_error(CanCan::Error, "Unable to merge an Active Record scope with other conditions. Instead use a hash or SQL for read Article ability.") end it "should not allow to fetch records when ability with just block present" do @ability.can :read, Article do false end - lambda { Article.accessible_by(@ability) }.should raise_error(CanCan::Error) + expect(lambda { Article.accessible_by(@ability) }).to raise_error(CanCan::Error) end it "should support more than one deeply nested conditions" do @@ -189,40 +188,40 @@ it "should not allow to check ability on object against SQL conditions without block" do @ability.can :read, Article, ["secret=?", true] - lambda { @ability.can? :read, Article.new }.should raise_error(CanCan::Error) + expect(lambda { @ability.can? :read, Article.new }).to raise_error(CanCan::Error) end it "should have false conditions if no abilities match" do - @ability.model_adapter(Article, :read).conditions.should == "'t'='f'" + expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'") end it "should return false conditions for cannot clause" do @ability.cannot :read, Article - @ability.model_adapter(Article, :read).conditions.should == "'t'='f'" + expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'") end it "should return SQL for single `can` definition in front of default `cannot` condition" do @ability.cannot :read, Article @ability.can :read, Article, :published => false, :secret => true - @ability.model_adapter(Article, :read).conditions.should orderlessly_match(%Q["#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't']) + expect(@ability.model_adapter(Article, :read).conditions).to orderlessly_match(%Q["#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't']) end it "should return true condition for single `can` definition in front of default `can` condition" do @ability.can :read, Article @ability.can :read, Article, :published => false, :secret => true - @ability.model_adapter(Article, :read).conditions.should == "'t'='t'" + expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='t'") end it "should return `false condition` for single `cannot` definition in front of default `cannot` condition" do @ability.cannot :read, Article @ability.cannot :read, Article, :published => false, :secret => true - @ability.model_adapter(Article, :read).conditions.should == "'t'='f'" + expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'") end it "should return `not (sql)` for single `cannot` definition in front of default `can` condition" do @ability.can :read, Article @ability.cannot :read, Article, :published => false, :secret => true - @ability.model_adapter(Article, :read).conditions.should orderlessly_match(%Q["not (#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't')]) + expect(@ability.model_adapter(Article, :read).conditions).to orderlessly_match(%Q["not (#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't')]) end it "should return appropriate sql conditions in complex case" do @@ -230,19 +229,19 @@ @ability.can :manage, Article, :id => 1 @ability.can :update, Article, :published => true @ability.cannot :update, Article, :secret => true - @ability.model_adapter(Article, :update).conditions.should == %Q[not ("#{@article_table}"."secret" = 't') AND (("#{@article_table}"."published" = 't') OR ("#{@article_table}"."id" = 1))] - @ability.model_adapter(Article, :manage).conditions.should == {:id => 1} - @ability.model_adapter(Article, :read).conditions.should == "'t'='t'" + expect(@ability.model_adapter(Article, :update).conditions).to eq(%Q[not ("#{@article_table}"."secret" = 't') AND (("#{@article_table}"."published" = 't') OR ("#{@article_table}"."id" = 1))]) + expect(@ability.model_adapter(Article, :manage).conditions).to eq({:id => 1}) + expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='t'") end it "should return appropriate sql conditions in complex case with nested joins" do @ability.can :read, Comment, :article => { :category => { :visible => true } } - @ability.model_adapter(Comment, :read).conditions.should == { Category.table_name.to_sym => { :visible => true } } + expect(@ability.model_adapter(Comment, :read).conditions).to eq({ Category.table_name.to_sym => { :visible => true } }) end it "should return appropriate sql conditions in complex case with nested joins of different depth" do @ability.can :read, Comment, :article => { :published => true, :category => { :visible => true } } - @ability.model_adapter(Comment, :read).conditions.should == { Article.table_name.to_sym => { :published => true }, Category.table_name.to_sym => { :visible => true } } + expect(@ability.model_adapter(Comment, :read).conditions).to eq({ Article.table_name.to_sym => { :published => true }, Category.table_name.to_sym => { :visible => true } }) end it "should not forget conditions when calling with SQL string" do @@ -250,36 +249,36 @@ @ability.can :read, Article, ['secret=?', false] adapter = @ability.model_adapter(Article, :read) 2.times do - adapter.conditions.should == %Q[(secret='f') OR ("#{@article_table}"."published" = 't')] + expect(adapter.conditions).to eq(%Q[(secret='f') OR ("#{@article_table}"."published" = 't')]) end end it "should have nil joins if no rules" do - @ability.model_adapter(Article, :read).joins.should be_nil + expect(@ability.model_adapter(Article, :read).joins).to be_nil end it "should have nil joins if no nested hashes specified in conditions" do @ability.can :read, Article, :published => false @ability.can :read, Article, :secret => true - @ability.model_adapter(Article, :read).joins.should be_nil + expect(@ability.model_adapter(Article, :read).joins).to be_nil end it "should merge separate joins into a single array" do @ability.can :read, Article, :project => { :blocked => false } @ability.can :read, Article, :company => { :admin => true } - @ability.model_adapter(Article, :read).joins.inspect.should orderlessly_match([:company, :project].inspect) + expect(@ability.model_adapter(Article, :read).joins.inspect).to orderlessly_match([:company, :project].inspect) end it "should merge same joins into a single array" do @ability.can :read, Article, :project => { :blocked => false } @ability.can :read, Article, :project => { :admin => true } - @ability.model_adapter(Article, :read).joins.should == [:project] + expect(@ability.model_adapter(Article, :read).joins).to eq([:project]) end it "should merge nested and non-nested joins" do @ability.can :read, Article, :project => { :blocked => false } @ability.can :read, Article, :project => { :comments => { :spam => true } } - @ability.model_adapter(Article, :read).joins.should == [{:project=>[:comments]}] + expect(@ability.model_adapter(Article, :read).joins).to eq([{:project=>[:comments]}]) end it "should merge :all conditions with other conditions" do @@ -288,16 +287,16 @@ ability = Ability.new(user) ability.can :manage, :all ability.can :manage, Article, :user_id => user.id - Article.accessible_by(ability).should == [article] + expect(Article.accessible_by(ability)).to eq([article]) end it "should restrict articles given a MetaWhere condition" do @ability.can :read, Article, :priority.lt => 2 article1 = Article.create!(:priority => 1) article2 = Article.create!(:priority => 3) - Article.accessible_by(@ability).should == [article1] - @ability.should be_able_to(:read, article1) - @ability.should_not be_able_to(:read, article2) + expect(Article.accessible_by(@ability)).to eq([article1]) + expect(@ability).to be_able_to(:read, article1) + expect(@ability).to_not be_able_to(:read, article2) end it "should merge MetaWhere and non-MetaWhere conditions" do @@ -305,44 +304,44 @@ @ability.can :read, Article, :priority => 1 article1 = Article.create!(:priority => 1) article2 = Article.create!(:priority => 3) - Article.accessible_by(@ability).should == [article1] - @ability.should be_able_to(:read, article1) - @ability.should_not be_able_to(:read, article2) + expect(Article.accessible_by(@ability)).to eq([article1]) + expect(@ability).to be_able_to(:read, article1) + expect(@ability).to_not be_able_to(:read, article2) end it "should match any MetaWhere condition" do adapter = CanCan::ModelAdapters::ActiveRecordAdapter article1 = Article.new(:priority => 1, :name => "Hello World") - adapter.matches_condition?(article1, :priority.eq, 1).should be_true - adapter.matches_condition?(article1, :priority.eq, 2).should be_false - adapter.matches_condition?(article1, :priority.eq_any, [1, 2]).should be_true - adapter.matches_condition?(article1, :priority.eq_any, [2, 3]).should be_false - adapter.matches_condition?(article1, :priority.eq_all, [1, 1]).should be_true - adapter.matches_condition?(article1, :priority.eq_all, [1, 2]).should be_false - adapter.matches_condition?(article1, :priority.ne, 2).should be_true - adapter.matches_condition?(article1, :priority.ne, 1).should be_false - adapter.matches_condition?(article1, :priority.in, [1, 2]).should be_true - adapter.matches_condition?(article1, :priority.in, [2, 3]).should be_false - adapter.matches_condition?(article1, :priority.nin, [2, 3]).should be_true - adapter.matches_condition?(article1, :priority.nin, [1, 2]).should be_false - adapter.matches_condition?(article1, :priority.lt, 2).should be_true - adapter.matches_condition?(article1, :priority.lt, 1).should be_false - adapter.matches_condition?(article1, :priority.lteq, 1).should be_true - adapter.matches_condition?(article1, :priority.lteq, 0).should be_false - adapter.matches_condition?(article1, :priority.gt, 0).should be_true - adapter.matches_condition?(article1, :priority.gt, 1).should be_false - adapter.matches_condition?(article1, :priority.gteq, 1).should be_true - adapter.matches_condition?(article1, :priority.gteq, 2).should be_false - adapter.matches_condition?(article1, :name.like, "%ello worl%").should be_true - adapter.matches_condition?(article1, :name.like, "hello world").should be_true - adapter.matches_condition?(article1, :name.like, "hello%").should be_true - adapter.matches_condition?(article1, :name.like, "h%d").should be_true - adapter.matches_condition?(article1, :name.like, "%helo%").should be_false - adapter.matches_condition?(article1, :name.like, "hello").should be_false - adapter.matches_condition?(article1, :name.like, "hello.world").should be_false + expect(adapter.matches_condition?(article1, :priority.eq, 1)).to be_true + expect(adapter.matches_condition?(article1, :priority.eq, 2)).to be_false + expect(adapter.matches_condition?(article1, :priority.eq_any, [1, 2])).to be_true + expect(adapter.matches_condition?(article1, :priority.eq_any, [2, 3])).to be_false + expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 1])).to be_true + expect(adapter.matches_condition?(article1, :priority.eq_all, [1, 2])).to be_false + expect(adapter.matches_condition?(article1, :priority.ne, 2)).to be_true + expect(adapter.matches_condition?(article1, :priority.ne, 1)).to be_false + expect(adapter.matches_condition?(article1, :priority.in, [1, 2])).to be_true + expect(adapter.matches_condition?(article1, :priority.in, [2, 3])).to be_false + expect(adapter.matches_condition?(article1, :priority.nin, [2, 3])).to be_true + expect(adapter.matches_condition?(article1, :priority.nin, [1, 2])).to be_false + expect(adapter.matches_condition?(article1, :priority.lt, 2)).to be_true + expect(adapter.matches_condition?(article1, :priority.lt, 1)).to be_false + expect(adapter.matches_condition?(article1, :priority.lteq, 1)).to be_true + expect(adapter.matches_condition?(article1, :priority.lteq, 0)).to be_false + expect(adapter.matches_condition?(article1, :priority.gt, 0)).to be_true + expect(adapter.matches_condition?(article1, :priority.gt, 1)).to be_false + expect(adapter.matches_condition?(article1, :priority.gteq, 1)).to be_true + expect(adapter.matches_condition?(article1, :priority.gteq, 2)).to be_false + expect(adapter.matches_condition?(article1, :name.like, "%ello worl%")).to be_true + expect(adapter.matches_condition?(article1, :name.like, "hello world")).to be_true + expect(adapter.matches_condition?(article1, :name.like, "hello%")).to be_true + expect(adapter.matches_condition?(article1, :name.like, "h%d")).to be_true + expect(adapter.matches_condition?(article1, :name.like, "%helo%")).to be_false + expect(adapter.matches_condition?(article1, :name.like, "hello")).to be_false + expect(adapter.matches_condition?(article1, :name.like, "hello.world")).to be_false # For some reason this is reporting "The not_matches MetaWhere condition is not supported." - # adapter.matches_condition?(article1, :name.nlike, "%helo%").should be_true - # adapter.matches_condition?(article1, :name.nlike, "%ello worl%").should be_false + # expect(adapter.matches_condition?(article1, :name.nlike, "%helo%")).to be_true + # expect(adapter.matches_condition?(article1, :name.nlike, "%ello worl%")).to be_false end it 'should not execute a scope when checking ability on the class' do diff --git a/spec/cancan/model_adapters/data_mapper_adapter_spec.rb b/spec/cancan/model_adapters/data_mapper_adapter_spec.rb index 6c6c7f18..faec520b 100644 --- a/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +++ b/spec/cancan/model_adapters/data_mapper_adapter_spec.rb @@ -26,8 +26,7 @@ class Comment before(:each) do Article.destroy Comment.destroy - @ability = Object.new - @ability.extend(CanCan::Ability) + (@ability = double).extend(CanCan::Ability) end it "should be for only data mapper classes" do diff --git a/spec/cancan/model_adapters/default_adapter_spec.rb b/spec/cancan/model_adapters/default_adapter_spec.rb index b257353c..27943e42 100644 --- a/spec/cancan/model_adapters/default_adapter_spec.rb +++ b/spec/cancan/model_adapters/default_adapter_spec.rb @@ -2,6 +2,6 @@ describe CanCan::ModelAdapters::DefaultAdapter do it "should be default for generic classes" do - CanCan::ModelAdapters::AbstractAdapter.adapter_class(Object).should == CanCan::ModelAdapters::DefaultAdapter + expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Object)).to eq(CanCan::ModelAdapters::DefaultAdapter) end end diff --git a/spec/cancan/model_adapters/mongoid_adapter_spec.rb b/spec/cancan/model_adapters/mongoid_adapter_spec.rb index 81ce4a67..77b6426f 100644 --- a/spec/cancan/model_adapters/mongoid_adapter_spec.rb +++ b/spec/cancan/model_adapters/mongoid_adapter_spec.rb @@ -20,8 +20,7 @@ class MongoidProject describe CanCan::ModelAdapters::MongoidAdapter do context "Mongoid defined" do before(:each) do - @ability = Object.new - @ability.extend(CanCan::Ability) + (@ability = double).extend(CanCan::Ability) end after(:each) do diff --git a/spec/cancan/rule_spec.rb b/spec/cancan/rule_spec.rb index 9c612cb8..643b65ad 100644 --- a/spec/cancan/rule_spec.rb +++ b/spec/cancan/rule_spec.rb @@ -9,44 +9,44 @@ end it "should return no association joins if none exist" do - @rule.associations_hash.should == {} + expect(@rule.associations_hash).to eq({}) end it "should return no association for joins if just attributes" do @conditions[:foo] = :bar - @rule.associations_hash.should == {} + expect(@rule.associations_hash).to eq({}) end it "should return single association for joins" do @conditions[:foo] = {:bar => 1} - @rule.associations_hash.should == {:foo => {}} + expect(@rule.associations_hash).to eq({:foo => {}}) end it "should return multiple associations for joins" do @conditions[:foo] = {:bar => 1} @conditions[:test] = {1 => 2} - @rule.associations_hash.should == {:foo => {}, :test => {}} + expect(@rule.associations_hash).to eq({:foo => {}, :test => {}}) end it "should return nested associations for joins" do @conditions[:foo] = {:bar => {1 => 2}} - @rule.associations_hash.should == {:foo => {:bar => {}}} + expect(@rule.associations_hash).to eq({:foo => {:bar => {}}}) end it "should return no association joins if conditions is nil" do rule = CanCan::Rule.new(true, :read, Integer, nil, nil) - rule.associations_hash.should == {} + expect(rule.associations_hash).to eq({}) end it "should not be mergeable if conditions are not simple hashes" do meta_where = OpenStruct.new(:name => 'metawhere', :column => 'test') @conditions[meta_where] = :bar - @rule.should be_unmergeable + expect(@rule).to be_unmergeable end it "should be mergeable if conditions is an empty hash" do @conditions = {} - @rule.should_not be_unmergeable + expect(@rule).to_not be_unmergeable end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 97169cc1..f45139e4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -12,7 +12,12 @@ config.treat_symbols_as_metadata_keys_with_true_values = true config.filter_run :focus => true config.run_all_when_everything_filtered = true - config.mock_with :rr + config.mock_with :rspec + + config.expect_with :rspec do |c| + c.syntax = :expect + end + config.before(:each) do Project.delete_all Category.delete_all From a30dfb2755fa1ce7b49b1f1c8b204e99a05d516c Mon Sep 17 00:00:00 2001 From: Oleg German Date: Tue, 23 Jul 2013 21:32:40 +0400 Subject: [PATCH 14/22] ruby 1.8 style hash syntax --- spec/cancan/ability_spec.rb | 6 +++--- spec/cancan/controller_resource_spec.rb | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/cancan/ability_spec.rb b/spec/cancan/ability_spec.rb index 8d38103b..fce9bcd6 100644 --- a/spec/cancan/ability_spec.rb +++ b/spec/cancan/ability_spec.rb @@ -254,15 +254,15 @@ end it "should accept a set as a condition value" do - expect(object_with_foo_2 = double(foo: 2)).to receive(:foo) - expect(object_with_foo_3 = double(foo: 3)).to receive(:foo) + expect(object_with_foo_2 = double(:foo => 2)).to receive(:foo) + expect(object_with_foo_3 = double(:foo => 3)).to receive(:foo) @ability.can :read, Object, :foo => [1, 2, 5].to_set expect(@ability.can?(:read, object_with_foo_2)).to be_true expect(@ability.can?(:read, object_with_foo_3)).to be_false end it "should not match subjects return nil for methods that must match nested a nested conditions hash" do - (object_with_foo = double(foo: :bar)).should_receive(:foo) + (object_with_foo = double(:foo => :bar)).should_receive(:foo) @ability.can :read, Array, :first => { :foo => :bar } expect(@ability.can?(:read, [object_with_foo])).to be_true expect(@ability.can?(:read, [])).to be_false diff --git a/spec/cancan/controller_resource_spec.rb b/spec/cancan/controller_resource_spec.rb index 103a2a8e..a88785d3 100644 --- a/spec/cancan/controller_resource_spec.rb +++ b/spec/cancan/controller_resource_spec.rb @@ -249,7 +249,7 @@ class Section it "should load resource through the association of another parent resource using instance variable" do @params.merge!(:action => "show", :id => "123") - category = double(projects: {}) + category = double(:projects => {}) @controller.instance_variable_set(:@category, category) allow(category.projects).to receive(:find).with("123") { :some_project } resource = CanCan::ControllerResource.new(@controller, :through => :category) @@ -259,7 +259,7 @@ class Section it "should load resource through the custom association name" do @params.merge!(:action => "show", :id => "123") - category = double(custom_projects: {}) + category = double(:custom_projects => {}) @controller.instance_variable_set(:@category, category) allow(category.custom_projects).to receive(:find).with("123") { :some_project } resource = CanCan::ControllerResource.new(@controller, :through => :category, :through_association => :custom_projects) @@ -269,7 +269,7 @@ class Section it "should load resource through the association of another parent resource using method" do @params.merge!(:action => "show", :id => "123") - category = double(projects: {}) + category = double(:projects => {}) allow(@controller).to receive(:category) { category } allow(category.projects).to receive(:find).with("123") { :some_project } resource = CanCan::ControllerResource.new(@controller, :through => :category) @@ -308,7 +308,7 @@ class Section it "should load through first matching if multiple are given" do @params.merge!(:action => "show", :id => "123") - category = double(projects: {}) + category = double(:projects => {}) @controller.instance_variable_set(:@category, category) allow(category.projects).to receive(:find).with("123") { :some_project } resource = CanCan::ControllerResource.new(@controller, :through => [:category, :user]) @@ -318,7 +318,7 @@ class Section it "should find record through has_one association with :singleton option without id param" do @params.merge!(:action => "show", :id => nil) - category = double(project: :some_project) + category = double(:project => :some_project) @controller.instance_variable_set(:@category, category) resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true) resource.load_resource From be24a2c8ae187e67c4ba52b7455f4d1c5b25a26a Mon Sep 17 00:00:00 2001 From: Oleg German Date: Thu, 25 Jul 2013 04:26:59 +0400 Subject: [PATCH 15/22] use expect syntax for Mongoid and DataMappper specs --- .../data_mapper_adapter_spec.rb | 36 ++++----- .../model_adapters/mongoid_adapter_spec.rb | 76 +++++++++---------- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/spec/cancan/model_adapters/data_mapper_adapter_spec.rb b/spec/cancan/model_adapters/data_mapper_adapter_spec.rb index faec520b..bde0fc78 100644 --- a/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +++ b/spec/cancan/model_adapters/data_mapper_adapter_spec.rb @@ -30,32 +30,32 @@ class Comment end it "should be for only data mapper classes" do - CanCan::ModelAdapters::DataMapperAdapter.should_not be_for_class(Object) - CanCan::ModelAdapters::DataMapperAdapter.should be_for_class(Article) - CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::DataMapperAdapter + expect(CanCan::ModelAdapters::DataMapperAdapter).not_to be_for_class(Object) + expect(CanCan::ModelAdapters::DataMapperAdapter).to be_for_class(Article) + expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)).to eq(CanCan::ModelAdapters::DataMapperAdapter) end it "should find record" do article = Article.create - CanCan::ModelAdapters::DataMapperAdapter.find(Article, article.id).should == article + expect(CanCan::ModelAdapters::DataMapperAdapter.find(Article, article.id)).to eq(article) end it "should not fetch any records when no abilities are defined" do Article.create - Article.accessible_by(@ability).should be_empty + expect(Article.accessible_by(@ability)).to be_empty end it "should fetch all articles when one can read all" do @ability.can :read, Article article = Article.create - Article.accessible_by(@ability).should == [article] + expect(Article.accessible_by(@ability)).to eq([article]) end it "should fetch only the articles that are published" do @ability.can :read, Article, :published => true article1 = Article.create(:published => true) article2 = Article.create(:published => false) - Article.accessible_by(@ability).should == [article1] + expect(Article.accessible_by(@ability)).to eq([article1]) end it "should fetch any articles which are published or secret" do @@ -65,7 +65,7 @@ class Comment article2 = Article.create(:published => true, :secret => true) article3 = Article.create(:published => false, :secret => true) article4 = Article.create(:published => false, :secret => false) - Article.accessible_by(@ability).should == [article1, article2, article3] + expect(Article.accessible_by(@ability)).to eq([article1, article2, article3]) end it "should fetch only the articles that are published and not secret" do @@ -75,14 +75,14 @@ class Comment article2 = Article.create(:published => true, :secret => true) article3 = Article.create(:published => false, :secret => true) article4 = Article.create(:published => false, :secret => false) - Article.accessible_by(@ability).should == [article1] + expect(Article.accessible_by(@ability)).to eq([article1]) end it "should only read comments for articles which are published" do @ability.can :read, Comment, :article => { :published => true } comment1 = Comment.create(:article => Article.create!(:published => true)) comment2 = Comment.create(:article => Article.create!(:published => false)) - Comment.accessible_by(@ability).should == [comment1] + expect(Comment.accessible_by(@ability)).to eq([comment1]) end it "should allow conditions in SQL and merge with hash conditions" do @@ -90,16 +90,16 @@ class Comment @ability.can :read, Article, ["secret=?", true] article1 = Article.create(:published => true, :secret => false) article4 = Article.create(:published => false, :secret => false) - Article.accessible_by(@ability).should == [article1] + expect(Article.accessible_by(@ability)).to eq([article1]) end it "should match gt comparison" do @ability.can :read, Article, :priority.gt => 3 article1 = Article.create(:priority => 4) article2 = Article.create(:priority => 3) - Article.accessible_by(@ability).should == [article1] - @ability.should be_able_to(:read, article1) - @ability.should_not be_able_to(:read, article2) + expect(Article.accessible_by(@ability)).to eq([article1]) + expect(@ability).to be_able_to(:read, article1) + expect(@ability).not_to be_able_to(:read, article2) end it "should match gte comparison" do @@ -107,10 +107,10 @@ class Comment article1 = Article.create(:priority => 4) article2 = Article.create(:priority => 3) article3 = Article.create(:priority => 2) - Article.accessible_by(@ability).should == [article1, article2] - @ability.should be_able_to(:read, article1) - @ability.should be_able_to(:read, article2) - @ability.should_not be_able_to(:read, article3) + expect(Article.accessible_by(@ability)).to eq([article1, article2]) + expect(@ability).to be_able_to(:read, article1) + expect(@ability).to be_able_to(:read, article2) + expect(@ability).not_to be_able_to(:read, article3) end # TODO: add more comparison specs diff --git a/spec/cancan/model_adapters/mongoid_adapter_spec.rb b/spec/cancan/model_adapters/mongoid_adapter_spec.rb index 77b6426f..c01b6da5 100644 --- a/spec/cancan/model_adapters/mongoid_adapter_spec.rb +++ b/spec/cancan/model_adapters/mongoid_adapter_spec.rb @@ -30,20 +30,20 @@ class MongoidProject end it "should be for only Mongoid classes" do - CanCan::ModelAdapters::MongoidAdapter.should_not be_for_class(Object) - CanCan::ModelAdapters::MongoidAdapter.should be_for_class(MongoidProject) - CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoidProject).should == CanCan::ModelAdapters::MongoidAdapter + expect(CanCan::ModelAdapters::MongoidAdapter).not_to be_for_class(Object) + expect(CanCan::ModelAdapters::MongoidAdapter).to be_for_class(MongoidProject) + expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoidProject)).to eq(CanCan::ModelAdapters::MongoidAdapter) end it "should find record" do project = MongoidProject.create - CanCan::ModelAdapters::MongoidAdapter.find(MongoidProject, project.id).should == project + expect(CanCan::ModelAdapters::MongoidAdapter.find(MongoidProject, project.id)).to eq(project) end it "should compare properties on mongoid documents with the conditions hash" do model = MongoidProject.new @ability.can :read, MongoidProject, :id => model.id - @ability.should be_able_to(:read, model) + expect(@ability).to be_able_to(:read, model) end it "should be able to read hashes when field is array" do @@ -51,8 +51,8 @@ class MongoidProject two_to_five = MongoidProject.create(:numbers => ['two', 'three', 'four', 'five']) @ability.can :foo, MongoidProject, :numbers => 'one' - @ability.should be_able_to(:foo, one_to_three) - @ability.should_not be_able_to(:foo, two_to_five) + expect(@ability).to be_able_to(:foo, one_to_three) + expect(@ability).not_to be_able_to(:foo, two_to_five) end it "should return [] when no ability is defined so no records are found" do @@ -60,7 +60,7 @@ class MongoidProject MongoidProject.create(:title => 'Lord') MongoidProject.create(:title => 'Dude') - MongoidProject.accessible_by(@ability, :read).entries.should == [] + expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([]) end it "should return the correct records based on the defined ability" do @@ -69,7 +69,7 @@ class MongoidProject lord = MongoidProject.create(:title => 'Lord') dude = MongoidProject.create(:title => 'Dude') - MongoidProject.accessible_by(@ability, :read).entries.should == [sir] + expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir]) end it "should return the correct records when a mix of can and cannot rules in defined ability" do @@ -80,7 +80,7 @@ class MongoidProject lord = MongoidProject.create(:title => 'Lord') dude = MongoidProject.create(:title => 'Dude') - MongoidProject.accessible_by(@ability, :destroy).entries.should == [sir] + expect(MongoidProject.accessible_by(@ability, :destroy).entries).to eq([sir]) end it "should be able to mix empty conditions and hashes" do @@ -89,7 +89,7 @@ class MongoidProject sir = MongoidProject.create(:title => 'Sir') lord = MongoidProject.create(:title => 'Lord') - MongoidProject.accessible_by(@ability, :read).count.should == 2 + expect(MongoidProject.accessible_by(@ability, :read).count).to eq(2) end it "should return everything when the defined ability is manage all" do @@ -98,7 +98,7 @@ class MongoidProject lord = MongoidProject.create(:title => 'Lord') dude = MongoidProject.create(:title => 'Dude') - MongoidProject.accessible_by(@ability, :read).entries.should == [sir, lord, dude] + expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir, lord, dude]) end it "should allow a scope for conditions" do @@ -107,18 +107,18 @@ class MongoidProject lord = MongoidProject.create(:title => 'Lord') dude = MongoidProject.create(:title => 'Dude') - MongoidProject.accessible_by(@ability, :read).entries.should == [sir] + expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir]) end describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do it "should handle :field.in" do obj = MongoidProject.create(:title => 'Sir') @ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"] - @ability.can?(:read, obj).should == true - MongoidProject.accessible_by(@ability, :read).should == [obj] + expect(@ability.can?(:read, obj)).to eq(true) + expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj]) obj2 = MongoidProject.create(:title => 'Lord') - @ability.can?(:read, obj2).should == false + expect(@ability.can?(:read, obj2)).to be_false end describe "activates only when there are Criteria in the hash" do @@ -127,73 +127,73 @@ class MongoidProject @conditions = {:title.nin => ["Fork", "Spoon"]} @ability.can :read, MongoidProject, @conditions - @ability.should be_able_to(:read, obj) + expect(@ability).to be_able_to(:read, obj) end it "Calls the base version if there are no mongoid criteria" do obj = MongoidProject.new(:title => 'Bird') @conditions = {:id => obj.id} @ability.can :read, MongoidProject, @conditions - @ability.should be_able_to(:read, obj) + expect(@ability).to be_able_to(:read, obj) end end it "should handle :field.nin" do obj = MongoidProject.create(:title => 'Sir') @ability.can :read, MongoidProject, :title.nin => ["Lord", "Madam"] - @ability.can?(:read, obj).should == true - MongoidProject.accessible_by(@ability, :read).should == [obj] + expect(@ability.can?(:read, obj)).to eq(true) + expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj]) obj2 = MongoidProject.create(:title => 'Lord') - @ability.can?(:read, obj2).should == false + expect(@ability.can?(:read, obj2)).to be_false end it "should handle :field.size" do obj = MongoidProject.create(:titles => ['Palatin', 'Margrave']) @ability.can :read, MongoidProject, :titles.size => 2 - @ability.can?(:read, obj).should == true - MongoidProject.accessible_by(@ability, :read).should == [obj] + expect(@ability.can?(:read, obj)).to eq(true) + expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj]) obj2 = MongoidProject.create(:titles => ['Palatin', 'Margrave', 'Marquis']) - @ability.can?(:read, obj2).should == false + expect(@ability.can?(:read, obj2)).to be_false end it "should handle :field.exists" do obj = MongoidProject.create(:titles => ['Palatin', 'Margrave']) @ability.can :read, MongoidProject, :titles.exists => true - @ability.can?(:read, obj).should == true - MongoidProject.accessible_by(@ability, :read).should == [obj] + expect(@ability.can?(:read, obj)).to eq(true) + expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj]) obj2 = MongoidProject.create - @ability.can?(:read, obj2).should == false + expect(@ability.can?(:read, obj2)).to be_false end it "should handle :field.gt" do obj = MongoidProject.create(:age => 50) @ability.can :read, MongoidProject, :age.gt => 45 - @ability.can?(:read, obj).should == true - MongoidProject.accessible_by(@ability, :read).should == [obj] + expect(@ability.can?(:read, obj)).to eq(true) + expect(MongoidProject.accessible_by(@ability, :read)).to eq([obj]) obj2 = MongoidProject.create(:age => 40) - @ability.can?(:read, obj2).should == false + expect(@ability.can?(:read, obj2)).to be_false end it "should handle instance not saved to database" do obj = MongoidProject.new(:title => 'Sir') @ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"] - @ability.can?(:read, obj).should == true + expect(@ability.can?(:read, obj)).to eq(true) # accessible_by only returns saved records - MongoidProject.accessible_by(@ability, :read).entries.should == [] + expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([]) obj2 = MongoidProject.new(:title => 'Lord') - @ability.can?(:read, obj2).should == false + expect(@ability.can?(:read, obj2)).to be_false end end it "should call where with matching ability conditions" do obj = MongoidProject.create(:foo => {:bar => 1}) @ability.can :read, MongoidProject, :foo => {:bar => 1} - MongoidProject.accessible_by(@ability, :read).entries.first.should == obj + expect(MongoidProject.accessible_by(@ability, :read).entries.first).to eq(obj) end it "should exclude from the result if set to cannot" do @@ -201,7 +201,7 @@ class MongoidProject obj2 = MongoidProject.create(:bar => 2) @ability.can :read, MongoidProject @ability.cannot :read, MongoidProject, :bar => 2 - MongoidProject.accessible_by(@ability, :read).entries.should == [obj] + expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([obj]) end it "should combine the rules" do @@ -210,16 +210,16 @@ class MongoidProject obj3 = MongoidProject.create(:bar => 3) @ability.can :read, MongoidProject, :bar => 1 @ability.can :read, MongoidProject, :bar => 2 - MongoidProject.accessible_by(@ability, :read).entries.should =~ [obj, obj2] + expect(MongoidProject.accessible_by(@ability, :read).entries).to match_array([obj, obj2]) end it "should not allow to fetch records when ability with just block present" do @ability.can :read, MongoidProject do false end - lambda { + expect { MongoidProject.accessible_by(@ability) - }.should raise_error(CanCan::Error) + }.to raise_error(CanCan::Error) end end end From b5bfda60c5ad4feda4c5bfe8e697e96ed062082f Mon Sep 17 00:00:00 2001 From: Ryan Bates Date: Sun, 22 Apr 2012 15:15:09 -0700 Subject: [PATCH 16/22] removed should spec wording, same as on the 2nd branch --- spec/cancan/ability_spec.rb | 116 +++++++++--------- spec/cancan/controller_additions_spec.rb | 40 +++--- spec/cancan/controller_resource_spec.rb | 114 ++++++++--------- spec/cancan/exceptions_spec.rb | 8 +- spec/cancan/inherited_resource_spec.rb | 12 +- .../active_record_adapter_spec.rb | 68 +++++----- .../data_mapper_adapter_spec.rb | 22 ++-- .../model_adapters/default_adapter_spec.rb | 2 +- .../model_adapters/mongoid_adapter_spec.rb | 40 +++--- spec/cancan/rule_spec.rb | 16 +-- 10 files changed, 219 insertions(+), 219 deletions(-) diff --git a/spec/cancan/ability_spec.rb b/spec/cancan/ability_spec.rb index fce9bcd6..5646eaab 100644 --- a/spec/cancan/ability_spec.rb +++ b/spec/cancan/ability_spec.rb @@ -5,17 +5,17 @@ (@ability = double).extend(CanCan::Ability) end - it "should be able to :read anything" do + it "is able to :read anything" do @ability.can :read, :all expect(@ability.can?(:read, String)).to be_true expect(@ability.can?(:read, 123)).to be_true end - it "should not have permission to do something it doesn't know about" do + it "does not have permission to do something it doesn't know about" do expect(@ability.can?(:foodfight, String)).to be_false end - it "should pass true to `can?` when non false/nil is returned in block" do + it "passes true to `can?` when non false/nil is returned in block" do @ability.can :read, :all @ability.can :read, Symbol do |sym| "foo" # TODO test that sym is nil when no instance is passed @@ -23,7 +23,7 @@ expect(@ability.can?(:read, :some_symbol)).to be_true end - it "should pass nil to a block when no instance is passed" do + it "passes nil to a block when no instance is passed" do @ability.can :read, Symbol do |sym| expect(sym).to be_nil true @@ -31,7 +31,7 @@ expect(@ability.can?(:read, Symbol)).to be_true end - it "should pass to previous rule, if block returns false or nil" do + it "passes to previous rule, if block returns false or nil" do @ability.can :read, Symbol @ability.can :read, Integer do |i| i < 5 @@ -45,7 +45,7 @@ expect(@ability.can?(:read, 6)).to be_false end - it "should not pass class with object if :all objects are accepted" do + it "does not pass class with object if :all objects are accepted" do @ability.can :preview, :all do |object| expect(object).to eq(123) @block_called = true @@ -54,7 +54,7 @@ expect(@block_called).to be_true end - it "should not call block when only class is passed, only return true" do + it "does not call block when only class is passed, only return true" do @block_called = false @ability.can :preview, :all do |object| @block_called = true @@ -63,7 +63,7 @@ expect(@block_called).to be_false end - it "should pass only object for global manage actions" do + it "passes only object for global manage actions" do @ability.can :manage, String do |object| expect(object).to eq("foo") @block_called = true @@ -72,25 +72,25 @@ expect(@block_called).to be_true end - it "should alias update or destroy actions to modify action" do + it "makes alias for update or destroy actions to modify action" do @ability.alias_action :update, :destroy, :to => :modify @ability.can :modify, :all expect(@ability.can?(:update, 123)).to be_true expect(@ability.can?(:destroy, 123)).to be_true end - it "should allow deeply nested aliased actions" do + it "allows deeply nested aliased actions" do @ability.alias_action :increment, :to => :sort @ability.alias_action :sort, :to => :modify @ability.can :modify, :all expect(@ability.can?(:increment, 123)).to be_true end - it "should raise an Error if alias target is an exist action" do + it "raises an Error if alias target is an exist action" do expect { @ability.alias_action :show, :to => :show }.to raise_error(CanCan::Error, "You can't specify target (show) as alias because it is real action name") end - it "should always call block with arguments when passing no arguments to can" do + it "always calls block with arguments when passing no arguments to can" do @ability.can do |action, object_class, object| expect(action).to eq(:foo) expect(object_class).to eq(123.class) @@ -101,7 +101,7 @@ expect(@block_called).to be_true end - it "should pass nil to object when comparing class with can check" do + it "passes nil to object when comparing class with can check" do @ability.can do |action, object_class, object| expect(action).to eq(:foo) expect(object_class).to eq(Hash) @@ -112,63 +112,63 @@ expect(@block_called).to be_true end - it "should automatically alias index and show into read calls" do + it "automatically makes alias for index and show into read calls" do @ability.can :read, :all expect(@ability.can?(:index, 123)).to be_true expect(@ability.can?(:show, 123)).to be_true end - it "should automatically alias new and edit into create and update respectively" do + it "automatically makes alias for new and edit into create and update respectively" do @ability.can :create, :all @ability.can :update, :all expect(@ability.can?(:new, 123)).to be_true expect(@ability.can?(:edit, 123)).to be_true end - it "should not respond to prepare (now using initialize)" do + it "does not respond to prepare (now using initialize)" do expect(@ability).to_not respond_to(:prepare) end - it "should offer cannot? method which is simply invert of can?" do + it "offers cannot? method which is simply invert of can?" do expect(@ability.cannot?(:tie, String)).to be_true end - it "should be able to specify multiple actions and match any" do + it "is able to specify multiple actions and match any" do @ability.can [:read, :update], :all expect(@ability.can?(:read, 123)).to be_true expect(@ability.can?(:update, 123)).to be_true expect(@ability.can?(:count, 123)).to be_false end - it "should be able to specify multiple classes and match any" do + it "is able to specify multiple classes and match any" do @ability.can :update, [String, Range] expect(@ability.can?(:update, "foo")).to be_true expect(@ability.can?(:update, 1..3)).to be_true expect(@ability.can?(:update, 123)).to be_false end - it "should support custom objects in the rule" do + it "supports custom objects in the rule" do @ability.can :read, :stats expect(@ability.can?(:read, :stats)).to be_true expect(@ability.can?(:update, :stats)).to be_false expect(@ability.can?(:read, :nonstats)).to be_false end - it "should check ancestors of class" do + it "checks ancestors of class" do @ability.can :read, Numeric expect(@ability.can?(:read, Integer)).to be_true expect(@ability.can?(:read, 1.23)).to be_true expect(@ability.can?(:read, "foo")).to be_false end - it "should support 'cannot' method to define what user cannot do" do + it "supports 'cannot' method to define what user cannot do" do @ability.can :read, :all @ability.cannot :read, Integer expect(@ability.can?(:read, "foo")).to be_true expect(@ability.can?(:read, 123)).to be_false end - it "should pass to previous rule, if block returns false or nil" do + it "passes to previous rule, if block returns false or nil" do @ability.can :read, :all @ability.cannot :read, Integer do |int| int > 10 ? nil : ( int > 5 ) @@ -179,7 +179,7 @@ expect(@ability.can?(:read, 123)).to be_true end - it "should always return `false` for single cannot definition" do + it "always returns `false` for single cannot definition" do @ability.cannot :read, Integer do |int| int > 10 ? nil : ( int > 5 ) end @@ -189,7 +189,7 @@ expect(@ability.can?(:read, 123)).to be_false end - it "should pass to previous cannot definition, if block returns false or nil" do + it "passes to previous cannot definition, if block returns false or nil" do @ability.cannot :read, :all @ability.can :read, Integer do |int| int > 10 ? nil : ( int > 5 ) @@ -200,19 +200,19 @@ expect(@ability.can?(:read, 123)).to be_false end - it "should append aliased actions" do + it "appends aliased actions" do @ability.alias_action :update, :to => :modify @ability.alias_action :destroy, :to => :modify expect(@ability.aliased_actions[:modify]).to eq([:update, :destroy]) end - it "should clear aliased actions" do + it "clears aliased actions" do @ability.alias_action :update, :to => :modify @ability.clear_aliased_actions expect(@ability.aliased_actions[:modify]).to be_nil end - it "should pass additional arguments to block from can?" do + it "passes additional arguments to block from can?" do @ability.can :read, Integer do |int, x| int > x end @@ -220,40 +220,40 @@ expect(@ability.can?(:read, 2, 3)).to be_false end - it "should use conditions as third parameter and determine abilities from it" do + it "uses conditions as third parameter and determine abilities from it" do @ability.can :read, Range, :begin => 1, :end => 3 expect(@ability.can?(:read, 1..3)).to be_true expect(@ability.can?(:read, 1..4)).to be_false expect(@ability.can?(:read, Range)).to be_true end - it "should allow an array of options in conditions hash" do + it "allows an array of options in conditions hash" do @ability.can :read, Range, :begin => [1, 3, 5] expect(@ability.can?(:read, 1..3)).to be_true expect(@ability.can?(:read, 2..4)).to be_false expect(@ability.can?(:read, 3..5)).to be_true end - it "should allow a range of options in conditions hash" do + it "allows a range of options in conditions hash" do @ability.can :read, Range, :begin => 1..3 expect(@ability.can?(:read, 1..10)).to be_true expect(@ability.can?(:read, 3..30)).to be_true expect(@ability.can?(:read, 4..40)).to be_false end - it "should allow nested hashes in conditions hash" do + it "allows nested hashes in conditions hash" do @ability.can :read, Range, :begin => { :to_i => 5 } expect(@ability.can?(:read, 5..7)).to be_true expect(@ability.can?(:read, 6..8)).to be_false end - it "should match any element passed in to nesting if it's an array (for has_many associations)" do + it "matches any element passed in to nesting if it's an array (for has_many associations)" do @ability.can :read, Range, :to_a => { :to_i => 3 } expect(@ability.can?(:read, 1..5)).to be_true expect(@ability.can?(:read, 4..6)).to be_false end - it "should accept a set as a condition value" do + it "accepts a set as a condition value" do expect(object_with_foo_2 = double(:foo => 2)).to receive(:foo) expect(object_with_foo_3 = double(:foo => 3)).to receive(:foo) @ability.can :read, Object, :foo => [1, 2, 5].to_set @@ -261,20 +261,20 @@ expect(@ability.can?(:read, object_with_foo_3)).to be_false end - it "should not match subjects return nil for methods that must match nested a nested conditions hash" do - (object_with_foo = double(:foo => :bar)).should_receive(:foo) + it "does not match subjects return nil for methods that must match nested a nested conditions hash" do + expect(object_with_foo = double(:foo => :bar)).to receive(:foo) @ability.can :read, Array, :first => { :foo => :bar } expect(@ability.can?(:read, [object_with_foo])).to be_true expect(@ability.can?(:read, [])).to be_false end - it "should match strings but not substrings specified in a conditions hash" do + it "matches strings but not substrings specified in a conditions hash" do @ability.can :read, String, :presence => "declassified" expect(@ability.can?(:read, "declassified")).to be_true expect(@ability.can?(:read, "classified")).to be_false end - it "should not stop at cannot definition when comparing class" do + it "does not stop at cannot definition when comparing class" do @ability.can :read, Range @ability.cannot :read, Range, :begin => 1 expect(@ability.can?(:read, 2..5)).to be_true @@ -282,14 +282,14 @@ expect(@ability.can?(:read, Range)).to be_true end - it "should stop at cannot definition when no hash is present" do + it "stops at cannot definition when no hash is present" do @ability.can :read, :all @ability.cannot :read, Range expect(@ability.can?(:read, 1..5)).to be_false expect(@ability.can?(:read, Range)).to be_false end - it "should allow to check ability for Module" do + it "allows to check ability for Module" do module B; end class A; include B; end @ability.can :read, B @@ -297,7 +297,7 @@ class A; include B; end expect(@ability.can?(:read, A.new)).to be_true end - it "should pass nil to a block for ability on Module when no instance is passed" do + it "passes nil to a block for ability on Module when no instance is passed" do module B; end class A; include B; end @ability.can :read, B do |sym| @@ -308,14 +308,14 @@ class A; include B; end expect(@ability.can?(:read, A)).to be_true end - it "passing a hash of subjects should check permissions through association" do + it "checks permissions through association when passing a hash of subjects" do @ability.can :read, Range, :string => {:length => 3} expect(@ability.can?(:read, "foo" => Range)).to be_true expect(@ability.can?(:read, "foobar" => Range)).to be_false expect(@ability.can?(:read, 123 => Range)).to be_true end - it "passing a hash of subjects with multiple definitions should check permissions correctly" do + it "checks permissions correctly when passing a hash of subjects with multiple definitions" do @ability.can :read, Range, :string => {:length => 4} @ability.can [:create, :read], Range, :string => {:upcase => 'FOO'} expect(@ability.can?(:read, "foo" => Range)).to be_true @@ -323,13 +323,13 @@ class A; include B; end expect(@ability.can?(:read, 1234 => Range)).to be_true end - it "should allow to check ability on Hash-like object" do + it "allows to check ability on Hash-like object" do class Container < Hash; end @ability.can :read, Container expect(@ability.can?(:read, Container.new)).to be_true end - it "should have initial attributes based on hash conditions of 'new' action" do + it "has initial attributes based on hash conditions of 'new' action" do @ability.can :manage, Range, :foo => "foo", :hash => {:skip => "hashes"} @ability.can :create, Range, :bar => 123, :array => %w[skip arrays] @ability.can :new, Range, :baz => "baz", :range => 1..3 @@ -337,7 +337,7 @@ class Container < Hash; end expect(@ability.attributes_for(:new, Range)).to eq({:foo => "foo", :bar => 123, :baz => "baz"}) end - it "should raise access denied exception if ability us unauthorized to perform a certain action" do + it "raises access denied exception if ability us unauthorized to perform a certain action" do begin @ability.authorize! :read, :foo, 1, 2, 3, :message => "Access denied!" rescue CanCan::AccessDenied => e @@ -349,14 +349,14 @@ class Container < Hash; end end end - it "should not raise access denied exception if ability is authorized to perform an action and return subject" do + it "does not raise access denied exception if ability is authorized to perform an action and return subject" do @ability.can :read, :foo expect { expect(@ability.authorize!(:read, :foo)).to eq(:foo) }.to_not raise_error end - it "should know when block is used in conditions" do + it "knows when block is used in conditions" do @ability.can :read, :foo expect(@ability).to_not have_block(:read, :foo) @ability.can :read, :foo do |foo| @@ -365,14 +365,14 @@ class Container < Hash; end expect(@ability).to have_block(:read, :foo) end - it "should know when raw sql is used in conditions" do + it "knows when raw sql is used in conditions" do @ability.can :read, :foo expect(@ability).to_not have_raw_sql(:read, :foo) @ability.can :read, :foo, 'false' expect(@ability).to have_raw_sql(:read, :foo) end - it "should raise access denied exception with default message if not specified" do + it "raises access denied exception with default message if not specified" do begin @ability.authorize! :read, :foo rescue CanCan::AccessDenied => e @@ -383,14 +383,14 @@ class Container < Hash; end end end - it "should determine model adapterO class by asking AbstractAdapter" do + it "determines model adapterO class by asking AbstractAdapter" do adapter_class, model_class = double, double allow(CanCan::ModelAdapters::AbstractAdapter).to receive(:adapter_class).with(model_class) { adapter_class } allow(adapter_class).to receive(:new).with(model_class, []) { :adapter_instance } expect(@ability.model_adapter(model_class, :read)).to eq(:adapter_instance) end - it "should raise an error when attempting to use a block with a hash condition since it's not likely what they want" do + it "raises an error when attempting to use a block with a hash condition since it's not likely what they want" do expect { @ability.can :read, Array, :published => true do false @@ -403,19 +403,19 @@ class Container < Hash; end I18n.backend = nil end - it "should use action/subject in i18n" do + it "uses action/subject in i18n" do I18n.backend.store_translations :en, :unauthorized => {:update => {:array => "foo"}} expect(@ability.unauthorized_message(:update, Array)).to eq("foo") expect(@ability.unauthorized_message(:update, [1, 2, 3])).to eq("foo") expect(@ability.unauthorized_message(:update, :missing)).to be_nil end - it "should use symbol as subject directly" do + it "uses symbol as subject directly" do I18n.backend.store_translations :en, :unauthorized => {:has => {:cheezburger => "Nom nom nom. I eated it."}} expect(@ability.unauthorized_message(:has, :cheezburger)).to eq("Nom nom nom. I eated it.") end - it "should fall back to 'manage' and 'all'" do + it "falls back to 'manage' and 'all'" do I18n.backend.store_translations :en, :unauthorized => { :manage => {:all => "manage all", :array => "manage array"}, :update => {:all => "update all", :array => "update array"} @@ -426,14 +426,14 @@ class Container < Hash; end expect(@ability.unauthorized_message(:foo, Hash)).to eq("manage all") end - it "should follow aliased actions" do + it "follows aliased actions" do I18n.backend.store_translations :en, :unauthorized => {:modify => {:array => "modify array"}} @ability.alias_action :update, :to => :modify expect(@ability.unauthorized_message(:update, Array)).to eq("modify array") expect(@ability.unauthorized_message(:edit, Array)).to eq("modify array") end - it "should have variables for action and subject" do + it "has variables for action and subject" do I18n.backend.store_translations :en, :unauthorized => {:manage => {:all => "%{action} %{subject}"}} # old syntax for now in case testing with old I18n expect(@ability.unauthorized_message(:update, Array)).to eq("update array") expect(@ability.unauthorized_message(:update, ArgumentError)).to eq("update argument error") @@ -442,7 +442,7 @@ class Container < Hash; end end describe "#merge" do - it "should add the rules from the given ability" do + it "adds the rules from the given ability" do @ability.can :use, :tools (another_ability = double).extend(CanCan::Ability) another_ability.can :use, :search diff --git a/spec/cancan/controller_additions_spec.rb b/spec/cancan/controller_additions_spec.rb index c1ed6820..05a59cc0 100644 --- a/spec/cancan/controller_additions_spec.rb +++ b/spec/cancan/controller_additions_spec.rb @@ -10,73 +10,73 @@ @controller_class.send(:include, CanCan::ControllerAdditions) end - it "should raise ImplementationRemoved when attempting to call 'unauthorized!' on a controller" do + it "raises ImplementationRemoved when attempting to call 'unauthorized!' on a controller" do expect { @controller.unauthorized! }.to raise_error(CanCan::ImplementationRemoved) end - it "authorize! should assign @_authorized instance variable and pass args to current ability" do + it "authorize! assigns @_authorized instance variable and pass args to current ability" do allow(@controller.current_ability).to receive(:authorize!).with(:foo, :bar) @controller.authorize!(:foo, :bar) expect(@controller.instance_variable_get(:@_authorized)).to be_true end - it "should have a current_ability method which generates an ability for the current user" do + it "has a current_ability method which generates an ability for the current user" do expect(@controller.current_ability).to be_kind_of(Ability) end - it "should provide a can? and cannot? methods which go through the current ability" do + it "provides a can? and cannot? methods which go through the current ability" do expect(@controller.current_ability).to be_kind_of(Ability) expect(@controller.can?(:foo, :bar)).to be_false expect(@controller.cannot?(:foo, :bar)).to be_true end - it "load_and_authorize_resource should setup a before filter which passes call to ControllerResource" do + it "load_and_authorize_resource setups a before filter which passes call to ControllerResource" do expect(cancan_resource_class = double).to receive(:load_and_authorize_resource) allow(CanCan::ControllerResource).to receive(:new).with(@controller, nil, :foo => :bar) {cancan_resource_class } expect(@controller_class).to receive(:before_filter).with({}) { |options, &block| block.call(@controller) } @controller_class.load_and_authorize_resource :foo => :bar end - it "load_and_authorize_resource should properly pass first argument as the resource name" do + it "load_and_authorize_resource properly passes first argument as the resource name" do expect(cancan_resource_class = double).to receive(:load_and_authorize_resource) allow(CanCan::ControllerResource).to receive(:new).with(@controller, :project, :foo => :bar) {cancan_resource_class} expect(@controller_class).to receive(:before_filter).with({}) { |options, &block| block.call(@controller) } @controller_class.load_and_authorize_resource :project, :foo => :bar end - it "load_and_authorize_resource with :prepend should prepend the before filter" do + it "load_and_authorize_resource with :prepend prepends the before filter" do expect(@controller_class).to receive(:prepend_before_filter).with({}) @controller_class.load_and_authorize_resource :foo => :bar, :prepend => true end - it "authorize_resource should setup a before filter which passes call to ControllerResource" do + it "authorize_resource setups a before filter which passes call to ControllerResource" do expect(cancan_resource_class = double).to receive(:authorize_resource) allow(CanCan::ControllerResource).to receive(:new).with(@controller, nil, :foo => :bar) {cancan_resource_class} expect(@controller_class).to receive(:before_filter).with(:except => :show, :if => true) { |options, &block| block.call(@controller) } @controller_class.authorize_resource :foo => :bar, :except => :show, :if => true end - it "load_resource should setup a before filter which passes call to ControllerResource" do + it "load_resource setups a before filter which passes call to ControllerResource" do expect(cancan_resource_class = double).to receive(:load_resource) allow(CanCan::ControllerResource).to receive(:new).with(@controller, nil, :foo => :bar) {cancan_resource_class} expect(@controller_class).to receive(:before_filter).with(:only => [:show, :index], :unless => false) { |options, &block| block.call(@controller) } @controller_class.load_resource :foo => :bar, :only => [:show, :index], :unless => false end - it "skip_authorization_check should set up a before filter which sets @_authorized to true" do + it "skip_authorization_check setups a before filter which sets @_authorized to true" do expect(@controller_class).to receive(:before_filter).with(:filter_options) { |options, &block| block.call(@controller) } @controller_class.skip_authorization_check(:filter_options) expect(@controller.instance_variable_get(:@_authorized)).to be_true end - it "check_authorization should trigger AuthorizationNotPerformed in after filter" do + it "check_authorization triggers AuthorizationNotPerformed in after filter" do expect(@controller_class).to receive(:after_filter).with(:only => [:test]) { |options, &block| block.call(@controller) } expect { @controller_class.check_authorization(:only => [:test]) }.to raise_error(CanCan::AuthorizationNotPerformed) end - it "check_authorization should not trigger AuthorizationNotPerformed when :if is false" do + it "check_authorization does not trigger AuthorizationNotPerformed when :if is false" do allow(@controller).to receive(:check_auth?) { false } allow(@controller_class).to receive(:after_filter).with({}) { |options, &block| block.call(@controller) } expect { @@ -84,7 +84,7 @@ }.not_to raise_error end - it "check_authorization should not trigger AuthorizationNotPerformed when :unless is true" do + it "check_authorization does not trigger AuthorizationNotPerformed when :unless is true" do allow(@controller).to receive(:engine_controller?) { true } expect(@controller_class).to receive(:after_filter).with({}) { |options, &block| block.call(@controller) } expect { @@ -92,7 +92,7 @@ }.not_to raise_error end - it "check_authorization should not raise error when @_authorized is set" do + it "check_authorization does not raise error when @_authorized is set" do @controller.instance_variable_set(:@_authorized, true) expect(@controller_class).to receive(:after_filter).with(:only => [:test]) { |options, &block| block.call(@controller) } expect { @@ -100,22 +100,22 @@ }.not_to raise_error end - it "cancan_resource_class should be ControllerResource by default" do + it "cancan_resource_class is ControllerResource by default" do expect(@controller.class.cancan_resource_class).to eq(CanCan::ControllerResource) end - it "cancan_resource_class should be InheritedResource when class includes InheritedResources::Actions" do + it "cancan_resource_class is InheritedResource when class includes InheritedResources::Actions" do allow(@controller.class).to receive(:ancestors) { ["InheritedResources::Actions"] } expect(@controller.class.cancan_resource_class).to eq(CanCan::InheritedResource) end - it "cancan_skipper should be an empty hash with :authorize and :load options and remember changes" do + it "cancan_skipper is an empty hash with :authorize and :load options and remember changes" do expect(@controller_class.cancan_skipper).to eq({:authorize => {}, :load => {}}) @controller_class.cancan_skipper[:load] = true expect(@controller_class.cancan_skipper[:load]).to be_true end - it "skip_authorize_resource should add itself to the cancan skipper with given model name and options" do + it "skip_authorize_resource adds itself to the cancan skipper with given model name and options" do @controller_class.skip_authorize_resource(:project, :only => [:index, :show]) expect(@controller_class.cancan_skipper[:authorize][:project]).to eq({:only => [:index, :show]}) @controller_class.skip_authorize_resource(:only => [:index, :show]) @@ -124,7 +124,7 @@ expect(@controller_class.cancan_skipper[:authorize][:article]).to eq({}) end - it "skip_load_resource should add itself to the cancan skipper with given model name and options" do + it "skip_load_resource adds itself to the cancan skipper with given model name and options" do @controller_class.skip_load_resource(:project, :only => [:index, :show]) expect(@controller_class.cancan_skipper[:load][:project]).to eq({:only => [:index, :show]}) @controller_class.skip_load_resource(:only => [:index, :show]) @@ -133,7 +133,7 @@ expect(@controller_class.cancan_skipper[:load][:article]).to eq({}) end - it "skip_load_and_authore_resource should add itself to the cancan skipper with given model name and options" do + it "skip_load_and_authore_resource adds itself to the cancan skipper with given model name and options" do @controller_class.skip_load_and_authorize_resource(:project, :only => [:index, :show]) expect(@controller_class.cancan_skipper[:load][:project]).to eq({:only => [:index, :show]}) expect(@controller_class.cancan_skipper[:authorize][:project]).to eq({:only => [:index, :show]}) diff --git a/spec/cancan/controller_resource_spec.rb b/spec/cancan/controller_resource_spec.rb index a88785d3..e85e75e4 100644 --- a/spec/cancan/controller_resource_spec.rb +++ b/spec/cancan/controller_resource_spec.rb @@ -11,7 +11,7 @@ allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {}, :load => {}} } end - it "should load the resource into an instance variable if params[:id] is specified" do + it "loads the resource into an instance variable if params[:id] is specified" do project = Project.create! @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller) @@ -19,7 +19,7 @@ expect(@controller.instance_variable_get(:@project)).to eq(project) end - it "should not load resource into an instance variable if already set" do + it "does not load resource into an instance variable if already set" do @params.merge!(:action => "show", :id => "123") @controller.instance_variable_set(:@project, :some_project) resource = CanCan::ControllerResource.new(@controller) @@ -27,7 +27,7 @@ expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end - it "should properly load resource for namespaced controller" do + it "loads resource for namespaced controller" do project = Project.create! @params.merge!(:controller => "admin/projects", :action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller) @@ -35,7 +35,7 @@ expect(@controller.instance_variable_get(:@project)).to eq(project) end - it "should attempt to load a resource with the same namespace as the controller when using :: for namespace" do + it "attempts to load a resource with the same namespace as the controller when using :: for namespace" do module MyEngine class Project < ::Project; end end @@ -48,7 +48,7 @@ class Project < ::Project; end end # Rails includes namespace in params, see issue #349 - it "should create through the namespaced params" do + it "creates through the namespaced params" do module MyEngine class Project < ::Project; end end @@ -59,7 +59,7 @@ class Project < ::Project; end expect(@controller.instance_variable_get(:@project).name).to eq("foobar") end - it "should properly load resource for namespaced controller when using '::' for namespace" do + it "loads resource for namespaced controller when using '::' for namespace" do project = Project.create! @params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller) @@ -77,28 +77,28 @@ class Dashboard; end expect(resource.send(:resource_class)).to eq(Admin::Dashboard) end - it "should build a new resource with hash if params[:id] is not specified" do + it "builds a new resource with hash if params[:id] is not specified" do @params.merge!(:action => "create", :project => {:name => "foobar"}) resource = CanCan::ControllerResource.new(@controller) resource.load_resource expect(@controller.instance_variable_get(:@project).name).to eq("foobar") end - it "should build a new resource for namespaced model with hash if params[:id] is not specified" do + it "builds a new resource for namespaced model with hash if params[:id] is not specified" do @params.merge!(:action => "create", 'sub_project' => {:name => "foobar"}) resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project) resource.load_resource expect(@controller.instance_variable_get(:@project).name).to eq("foobar") end - it "should build a new resource for namespaced controller and namespaced model with hash if params[:id] is not specified" do + it "builds a new resource for namespaced controller and namespaced model with hash if params[:id] is not specified" do @params.merge!(:controller => "Admin::SubProjectsController", :action => "create", 'sub_project' => {:name => "foobar"}) resource = CanCan::ControllerResource.new(@controller, :class => Project) resource.load_resource expect(@controller.instance_variable_get(:@sub_project).name).to eq("foobar") end - it "should build a new resource with attributes from current ability" do + it "builds a new resource with attributes from current ability" do @params.merge!(:action => "new") @ability.can(:create, Project, :name => "from conditions") resource = CanCan::ControllerResource.new(@controller) @@ -106,7 +106,7 @@ class Dashboard; end expect(@controller.instance_variable_get(:@project).name).to eq("from conditions") end - it "should override initial attributes with params" do + it "overrides initial attributes with params" do @params.merge!(:action => "new", :project => {:name => "from params"}) @ability.can(:create, Project, :name => "from conditions") resource = CanCan::ControllerResource.new(@controller) @@ -114,7 +114,7 @@ class Dashboard; end expect(@controller.instance_variable_get(:@project).name).to eq("from params") end - it "should build a collection when on index action when class responds to accessible_by" do + it "builds a collection when on index action when class responds to accessible_by" do allow(Project).to receive(:accessible_by).with(@ability, :index) { :found_projects } @params[:action] = "index" resource = CanCan::ControllerResource.new(@controller, :project) @@ -123,7 +123,7 @@ class Dashboard; end expect(@controller.instance_variable_get(:@projects)).to eq(:found_projects) end - it "should not build a collection when on index action when class does not respond to accessible_by" do + it "does not build a collection when on index action when class does not respond to accessible_by" do @params[:action] = "index" resource = CanCan::ControllerResource.new(@controller) resource.load_resource @@ -131,7 +131,7 @@ class Dashboard; end expect(@controller.instance_variable_defined?(:@projects)).to be_false end - it "should not use accessible_by when defining abilities through a block" do + it "does not use accessible_by when defining abilities through a block" do allow(Project).to receive(:accessible_by).with(@ability) { :found_projects } @params[:action] = "index" @ability.can(:read, Project) { |p| false } @@ -141,7 +141,7 @@ class Dashboard; end expect(@controller.instance_variable_defined?(:@projects)).to be_false end - it "should not authorize single resource in collection action" do + it "does not authorize single resource in collection action" do @params[:action] = "index" @controller.instance_variable_set(:@project, :some_project) allow(@controller).to receive(:authorize!).with(:index, Project) { raise CanCan::AccessDenied } @@ -149,7 +149,7 @@ class Dashboard; end expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end - it "should authorize parent resource in collection action" do + it "authorizes parent resource in collection action" do @params[:action] = "index" @controller.instance_variable_set(:@category, :some_category) allow(@controller).to receive(:authorize!).with(:show, :some_category) { raise CanCan::AccessDenied } @@ -157,7 +157,7 @@ class Dashboard; end expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end - it "should perform authorization using controller action and loaded model" do + it "performs authorization using controller action and loaded model" do @params.merge!(:action => "show", :id => "123") @controller.instance_variable_set(:@project, :some_project) allow(@controller).to receive(:authorize!).with(:show, :some_project) { raise CanCan::AccessDenied } @@ -165,14 +165,14 @@ class Dashboard; end expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end - it "should perform authorization using controller action and non loaded model" do + it "performs authorization using controller action and non loaded model" do @params.merge!(:action => "show", :id => "123") allow(@controller).to receive(:authorize!).with(:show, Project) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller) expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end - it "should call load_resource and authorize_resource for load_and_authorize_resource" do + it "calls load_resource and authorize_resource for load_and_authorize_resource" do @params.merge!(:action => "show", :id => "123") resource = CanCan::ControllerResource.new(@controller) expect(resource).to receive(:load_resource) @@ -180,14 +180,14 @@ class Dashboard; end resource.load_and_authorize_resource end - it "should not build a single resource when on custom collection action even with id" do + it "does not build a single resource when on custom collection action even with id" do @params.merge!(:action => "sort", :id => "123") resource = CanCan::ControllerResource.new(@controller, :collection => [:sort, :list]) resource.load_resource expect(@controller.instance_variable_get(:@project)).to be_nil end - it "should load a collection resource when on custom action with no id param" do + it "loads a collection resource when on custom action with no id param" do allow(Project).to receive(:accessible_by).with(@ability, :sort) { :found_projects } @params[:action] = "sort" resource = CanCan::ControllerResource.new(@controller) @@ -196,7 +196,7 @@ class Dashboard; end expect(@controller.instance_variable_get(:@projects)).to eq(:found_projects) end - it "should build a resource when on custom new action even when params[:id] exists" do + it "builds a resource when on custom new action even when params[:id] exists" do @params.merge!(:action => "build", :id => "123") allow(Project).to receive(:new) { :some_project } resource = CanCan::ControllerResource.new(@controller, :new => :build) @@ -204,34 +204,34 @@ class Dashboard; end expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end - it "should not try to load resource for other action if params[:id] is undefined" do + it "does not try to load resource for other action if params[:id] is undefined" do @params[:action] = "list" resource = CanCan::ControllerResource.new(@controller) resource.load_resource expect(@controller.instance_variable_get(:@project)).to be_nil end - it "should be a parent resource when name is provided which doesn't match controller" do + it "is a parent resource when name is provided which doesn't match controller" do resource = CanCan::ControllerResource.new(@controller, :category) expect(resource).to be_parent end - it "should not be a parent resource when name is provided which matches controller" do + it "does not be a parent resource when name is provided which matches controller" do resource = CanCan::ControllerResource.new(@controller, :project) expect(resource).to_not be_parent end - it "should be parent if specified in options" do + it "is parent if specified in options" do resource = CanCan::ControllerResource.new(@controller, :project, {:parent => true}) expect(resource).to be_parent end - it "should not be parent if specified in options" do + it "does not be parent if specified in options" do resource = CanCan::ControllerResource.new(@controller, :category, {:parent => false}) expect(resource).to_not be_parent end - it "should have the specified resource_class if 'name' is passed to load_resource" do + it "has the specified resource_class if 'name' is passed to load_resource" do class Section end @@ -239,7 +239,7 @@ class Section expect(resource.send(:resource_class)).to eq(Section) end - it "should load parent resource through proper id parameter" do + it "loads parent resource through proper id parameter" do project = Project.create! @params.merge!(:controller => "categories", :action => "index", :project_id => project.id) resource = CanCan::ControllerResource.new(@controller, :project) @@ -247,7 +247,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(project) end - it "should load resource through the association of another parent resource using instance variable" do + it "loads resource through the association of another parent resource using instance variable" do @params.merge!(:action => "show", :id => "123") category = double(:projects => {}) @controller.instance_variable_set(:@category, category) @@ -257,7 +257,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end - it "should load resource through the custom association name" do + it "loads resource through the custom association name" do @params.merge!(:action => "show", :id => "123") category = double(:custom_projects => {}) @controller.instance_variable_set(:@category, category) @@ -267,7 +267,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end - it "should load resource through the association of another parent resource using method" do + it "loads resource through the association of another parent resource using method" do @params.merge!(:action => "show", :id => "123") category = double(:projects => {}) allow(@controller).to receive(:category) { category } @@ -277,7 +277,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end - it "should not load through parent resource if instance isn't loaded when shallow" do + it "does not load through parent resource if instance isn't loaded when shallow" do project = Project.create! @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :through => :category, :shallow => true) @@ -285,7 +285,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(project) end - it "should raise AccessDenied when attempting to load resource through nil" do + it "raises AccessDenied when attempting to load resource through nil" do project = Project.create! @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :through => :category) @@ -298,7 +298,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to be_nil end - it "should authorize nested resource through parent association on index action" do + it "authorizes nested resource through parent association on index action" do @params.merge!(:action => "index") @controller.instance_variable_set(:@category, category = double) allow(@controller).to receive(:authorize!).with(:index, category => Project) { raise CanCan::AccessDenied } @@ -306,7 +306,7 @@ class Section expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end - it "should load through first matching if multiple are given" do + it "loads through first matching if multiple are given" do @params.merge!(:action => "show", :id => "123") category = double(:projects => {}) @controller.instance_variable_set(:@category, category) @@ -316,7 +316,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end - it "should find record through has_one association with :singleton option without id param" do + it "finds record through has_one association with :singleton option without id param" do @params.merge!(:action => "show", :id => nil) category = double(:project => :some_project) @controller.instance_variable_set(:@category, category) @@ -325,7 +325,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(:some_project) end - it "should not build record through has_one association with :singleton option because it can cause it to delete it in the database" do + it "does not build record through has_one association with :singleton option because it can cause it to delete it in the database" do @params.merge!(:action => "create", :project => {:name => "foobar"}) category = Category.new @controller.instance_variable_set(:@category, category) @@ -335,7 +335,7 @@ class Section expect(@controller.instance_variable_get(:@project).category).to eq(category) end - it "should find record through has_one association with :singleton and :shallow options" do + it "finds record through has_one association with :singleton and :shallow options" do project = Project.create! @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true, :shallow => true) @@ -343,14 +343,14 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(project) end - it "should build record through has_one association with :singleton and :shallow options" do + it "builds record through has_one association with :singleton and :shallow options" do @params.merge!(:action => "create", :project => {:name => "foobar"}) resource = CanCan::ControllerResource.new(@controller, :through => :category, :singleton => true, :shallow => true) resource.load_resource expect(@controller.instance_variable_get(:@project).name).to eq("foobar") end - it "should only authorize :show action on parent resource" do + it "only authorizes :show action on parent resource" do project = Project.create! @params.merge!(:action => "new", :project_id => project.id) allow(@controller).to receive(:authorize!).with(:show, project) { raise CanCan::AccessDenied } @@ -358,7 +358,7 @@ class Section expect { resource.load_and_authorize_resource }.to raise_error(CanCan::AccessDenied) end - it "should load the model using a custom class" do + it "loads the model using a custom class" do project = Project.create! @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :class => Project) @@ -366,7 +366,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(project) end - it "should load the model using a custom namespaced class" do + it "loads the model using a custom namespaced class" do project = Sub::Project.create! @params.merge!(:action => "show", :id => project.id) resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project) @@ -374,14 +374,14 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(project) end - it "should authorize based on resource name if class is false" do + it "authorizes based on resource name if class is false" do @params.merge!(:action => "show", :id => "123") allow(@controller).to receive(:authorize!).with(:show, :project) { raise CanCan::AccessDenied } resource = CanCan::ControllerResource.new(@controller, :class => false) expect { resource.authorize_resource }.to raise_error(CanCan::AccessDenied) end - it "should load and authorize using custom instance name" do + it "loads and authorize using custom instance name" do project = Project.create! @params.merge!(:action => "show", :id => project.id) allow(@controller).to receive(:authorize!).with(:show, project) { raise CanCan::AccessDenied } @@ -390,7 +390,7 @@ class Section expect(@controller.instance_variable_get(:@custom_project)).to eq(project) end - it "should load resource using custom ID param" do + it "loads resource using custom ID param" do project = Project.create! @params.merge!(:action => "show", :the_project => project.id) resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project) @@ -399,7 +399,7 @@ class Section end # CVE-2012-5664 - it "should always convert id param to string" do + it "always converts id param to string" do @params.merge!(:action => "show", :the_project => { :malicious => "I am" }) resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project) expect(resource.send(:id_param).class).to eq(String) @@ -411,7 +411,7 @@ class Section resource.send(:id_param).class.should == NilClass end - it "should load resource using custom find_by attribute" do + it "loads resource using custom find_by attribute" do project = Project.create!(:name => "foo") @params.merge!(:action => "show", :id => "foo") resource = CanCan::ControllerResource.new(@controller, :find_by => :name) @@ -419,7 +419,7 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(project) end - it "should allow full find method to be passed into find_by option" do + it "allows full find method to be passed into find_by option" do project = Project.create!(:name => "foo") @params.merge!(:action => "show", :id => "foo") resource = CanCan::ControllerResource.new(@controller, :find_by => :find_by_name) @@ -427,25 +427,25 @@ class Section expect(@controller.instance_variable_get(:@project)).to eq(project) end - it "should raise ImplementationRemoved when adding :name option" do + it "raises ImplementationRemoved when adding :name option" do expect { CanCan::ControllerResource.new(@controller, :name => :foo) }.to raise_error(CanCan::ImplementationRemoved) end - it "should raise ImplementationRemoved exception when specifying :resource option since it is no longer used" do + it "raises ImplementationRemoved exception when specifying :resource option since it is no longer used" do expect { CanCan::ControllerResource.new(@controller, :resource => Project) }.to raise_error(CanCan::ImplementationRemoved) end - it "should raise ImplementationRemoved exception when passing :nested option" do + it "raises ImplementationRemoved exception when passing :nested option" do expect { CanCan::ControllerResource.new(@controller, :nested => :project) }.to raise_error(CanCan::ImplementationRemoved) end - it "should skip resource behavior for :only actions in array" do + it "skips resource behavior for :only actions in array" do allow(@controller_class).to receive(:cancan_skipper) { {:load => {nil => {:only => [:index, :show]}}} } @params.merge!(:action => "index") expect(CanCan::ControllerResource.new(@controller).skip?(:load)).to be_true @@ -456,7 +456,7 @@ class Section expect(CanCan::ControllerResource.new(@controller).skip?(:load)).to be_false end - it "should skip resource behavior for :only one action on resource" do + it "skips resource behavior for :only one action on resource" do allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {:project => {:only => :index}}} } @params.merge!(:action => "index") expect(CanCan::ControllerResource.new(@controller).skip?(:authorize)).to be_false @@ -465,7 +465,7 @@ class Section expect(CanCan::ControllerResource.new(@controller, :project).skip?(:authorize)).to be_false end - it "should skip resource behavior :except actions in array" do + it "skips resource behavior :except actions in array" do allow(@controller_class).to receive(:cancan_skipper) { {:load => {nil => {:except => [:index, :show]}}} } @params.merge!(:action => "index") expect(CanCan::ControllerResource.new(@controller).skip?(:load)).to be_false @@ -476,7 +476,7 @@ class Section expect(CanCan::ControllerResource.new(@controller, :some_resource).skip?(:load)).to be_false end - it "should skip resource behavior :except one action on resource" do + it "skips resource behavior :except one action on resource" do allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {:project => {:except => :index}}} } @params.merge!(:action => "index") expect(CanCan::ControllerResource.new(@controller, :project).skip?(:authorize)).to be_false @@ -485,7 +485,7 @@ class Section expect(CanCan::ControllerResource.new(@controller, :project).skip?(:authorize)).to be_true end - it "should skip loading and authorization" do + it "skips loading and authorization" do allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {nil => {}}, :load => {nil => {}}} } @params.merge!(:action => "new") resource = CanCan::ControllerResource.new(@controller) diff --git a/spec/cancan/exceptions_spec.rb b/spec/cancan/exceptions_spec.rb index e3daa4f3..e1b67796 100644 --- a/spec/cancan/exceptions_spec.rb +++ b/spec/cancan/exceptions_spec.rb @@ -6,12 +6,12 @@ @exception = CanCan::AccessDenied.new(nil, :some_action, :some_subject) end - it "should have action and subject accessors" do + it "has action and subject accessors" do expect(@exception.action).to eq(:some_action) expect(@exception.subject).to eq(:some_subject) end - it "should have a changable default message" do + it "has a changable default message" do expect(@exception.message).to eq("You are not authorized to access this page.") @exception.default_message = "Unauthorized!" expect(@exception.message).to eq("Unauthorized!") @@ -23,12 +23,12 @@ @exception = CanCan::AccessDenied.new("Access denied!") end - it "should have nil action and subject" do + it "has nil action and subject" do expect(@exception.action).to be_nil expect(@exception.subject).to be_nil end - it "should have passed message" do + it "has passed message" do expect(@exception.message).to eq("Access denied!") end end diff --git a/spec/cancan/inherited_resource_spec.rb b/spec/cancan/inherited_resource_spec.rb index 94b8d008..05f8842a 100644 --- a/spec/cancan/inherited_resource_spec.rb +++ b/spec/cancan/inherited_resource_spec.rb @@ -11,28 +11,28 @@ allow(@controller_class).to receive(:cancan_skipper) { {:authorize => {}, :load => {}} } end - it "show should load resource through @controller.resource" do + it "show loads resource through @controller.resource" do @params.merge!(:action => "show", :id => 123) allow(@controller).to receive(:resource) { :project_resource } CanCan::InheritedResource.new(@controller).load_resource expect(@controller.instance_variable_get(:@project)).to eq(:project_resource) end - it "new should load through @controller.build_resource" do + it "new loads through @controller.build_resource" do @params[:action] = "new" allow(@controller).to receive(:build_resource) { :project_resource } CanCan::InheritedResource.new(@controller).load_resource expect(@controller.instance_variable_get(:@project)).to eq(:project_resource) end - it "index should load through @controller.association_chain when parent" do + it "index loads through @controller.association_chain when parent" do @params[:action] = "index" allow(@controller).to receive(:association_chain) { @controller.instance_variable_set(:@project, :project_resource) } CanCan::InheritedResource.new(@controller, :parent => true).load_resource expect(@controller.instance_variable_get(:@project)).to eq(:project_resource) end - it "index should load through @controller.end_of_association_chain" do + it "index loads through @controller.end_of_association_chain" do @params[:action] = "index" allow(Project).to receive(:accessible_by).with(@ability, :index) { :projects } allow(@controller).to receive(:end_of_association_chain) { Project } @@ -40,7 +40,7 @@ expect(@controller.instance_variable_get(:@projects)).to eq(:projects) end - it "should build a new resource with attributes from current ability" do + it "builds a new resource with attributes from current ability" do @params[:action] = "new" @ability.can(:create, Project, :name => "from conditions") allow(@controller).to receive(:build_resource) { Struct.new(:name).new } @@ -49,7 +49,7 @@ expect(@controller.instance_variable_get(:@project).name).to eq("from conditions") end - it "should override initial attributes with params" do + it "overrides initial attributes with params" do @params.merge!(:action => "new", :project => {:name => "from params"}) @ability.can(:create, Project, :name => "from conditions") allow(@controller).to receive(:build_resource) { Struct.new(:name).new } diff --git a/spec/cancan/model_adapters/active_record_adapter_spec.rb b/spec/cancan/model_adapters/active_record_adapter_spec.rb index 1831a095..8ea9a601 100644 --- a/spec/cancan/model_adapters/active_record_adapter_spec.rb +++ b/spec/cancan/model_adapters/active_record_adapter_spec.rb @@ -57,36 +57,36 @@ @comment_table = Comment.table_name end - it "should be for only active record classes" do + it "is for only active record classes" do expect(CanCan::ModelAdapters::ActiveRecordAdapter).to_not be_for_class(Object) expect(CanCan::ModelAdapters::ActiveRecordAdapter).to be_for_class(Article) expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)).to eq(CanCan::ModelAdapters::ActiveRecordAdapter) end - it "should find record" do + it "finds record" do article = Article.create! expect(CanCan::ModelAdapters::ActiveRecordAdapter.find(Article, article.id)).to eq(article) end - it "should not fetch any records when no abilities are defined" do + it "does not fetch any records when no abilities are defined" do Article.create! expect(Article.accessible_by(@ability)).to be_empty end - it "should fetch all articles when one can read all" do + it "fetches all articles when one can read all" do @ability.can :read, Article article = Article.create! expect(Article.accessible_by(@ability)).to eq([article]) end - it "should fetch only the articles that are published" do + it "fetches only the articles that are published" do @ability.can :read, Article, :published => true article1 = Article.create!(:published => true) article2 = Article.create!(:published => false) expect(Article.accessible_by(@ability)).to eq([article1]) end - it "should fetch any articles which are published or secret" do + it "fetches any articles which are published or secret" do @ability.can :read, Article, :published => true @ability.can :read, Article, :secret => true article1 = Article.create!(:published => true, :secret => false) @@ -96,7 +96,7 @@ expect(Article.accessible_by(@ability)).to eq([article1, article2, article3]) end - it "should fetch only the articles that are published and not secret" do + it "fetches only the articles that are published and not secret" do @ability.can :read, Article, :published => true @ability.cannot :read, Article, :secret => true article1 = Article.create!(:published => true, :secret => false) @@ -106,7 +106,7 @@ expect(Article.accessible_by(@ability)).to eq([article1]) end - it "should only read comments for articles which are published" do + it "only reads comments for articles which are published" do @ability.can :read, Comment, :article => { :published => true } comment1 = Comment.create!(:article => Article.create!(:published => true)) comment2 = Comment.create!(:article => Article.create!(:published => false)) @@ -131,14 +131,14 @@ Category.accessible_by(@ability).should == [category] end - it "should only read comments for visible categories through articles" do + it "only reads comments for visible categories through articles" do @ability.can :read, Comment, :article => { :category => { :visible => true } } comment1 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => true))) comment2 = Comment.create!(:article => Article.create!(:category => Category.create!(:visible => false))) expect(Comment.accessible_by(@ability)).to eq([comment1]) end - it "should allow conditions in SQL and merge with hash conditions" do + it "allows conditions in SQL and merge with hash conditions" do @ability.can :read, Article, :published => true @ability.can :read, Article, ["secret=?", true] article1 = Article.create!(:published => true, :secret => false) @@ -148,14 +148,14 @@ expect(Article.accessible_by(@ability)).to eq([article1, article2, article3]) end - it "should allow a scope for conditions" do + it "allows a scope for conditions" do @ability.can :read, Article, Article.where(:secret => true) article1 = Article.create!(:secret => true) article2 = Article.create!(:secret => false) expect(Article.accessible_by(@ability)).to eq([article1]) end - it "should fetch only associated records when using with a scope for conditions" do + it "fetches only associated records when using with a scope for conditions" do @ability.can :read, Article, Article.where(:secret => true) category1 = Category.create!(:visible => false) category2 = Category.create!(:visible => true) @@ -164,13 +164,13 @@ expect(category1.articles.accessible_by(@ability)).to eq([article1]) end - it "should raise an exception when trying to merge scope with other conditions" do + it "raises an exception when trying to merge scope with other conditions" do @ability.can :read, Article, :published => true @ability.can :read, Article, Article.where(:secret => true) expect(lambda { Article.accessible_by(@ability) }).to raise_error(CanCan::Error, "Unable to merge an Active Record scope with other conditions. Instead use a hash or SQL for read Article ability.") end - it "should not allow to fetch records when ability with just block present" do + it "does not allow to fetch records when ability with just block present" do @ability.can :read, Article do false end @@ -186,45 +186,45 @@ expect { Comment.accessible_by(@ability) }.to_not raise_error end - it "should not allow to check ability on object against SQL conditions without block" do + it "does not allow to check ability on object against SQL conditions without block" do @ability.can :read, Article, ["secret=?", true] expect(lambda { @ability.can? :read, Article.new }).to raise_error(CanCan::Error) end - it "should have false conditions if no abilities match" do + it "has false conditions if no abilities match" do expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'") end - it "should return false conditions for cannot clause" do + it "returns false conditions for cannot clause" do @ability.cannot :read, Article expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'") end - it "should return SQL for single `can` definition in front of default `cannot` condition" do + it "returns SQL for single `can` definition in front of default `cannot` condition" do @ability.cannot :read, Article @ability.can :read, Article, :published => false, :secret => true expect(@ability.model_adapter(Article, :read).conditions).to orderlessly_match(%Q["#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't']) end - it "should return true condition for single `can` definition in front of default `can` condition" do + it "returns true condition for single `can` definition in front of default `can` condition" do @ability.can :read, Article @ability.can :read, Article, :published => false, :secret => true expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='t'") end - it "should return `false condition` for single `cannot` definition in front of default `cannot` condition" do + it "returns `false condition` for single `cannot` definition in front of default `cannot` condition" do @ability.cannot :read, Article @ability.cannot :read, Article, :published => false, :secret => true expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='f'") end - it "should return `not (sql)` for single `cannot` definition in front of default `can` condition" do + it "returns `not (sql)` for single `cannot` definition in front of default `can` condition" do @ability.can :read, Article @ability.cannot :read, Article, :published => false, :secret => true expect(@ability.model_adapter(Article, :read).conditions).to orderlessly_match(%Q["not (#{@article_table}"."published" = 'f' AND "#{@article_table}"."secret" = 't')]) end - it "should return appropriate sql conditions in complex case" do + it "returns appropriate sql conditions in complex case" do @ability.can :read, Article @ability.can :manage, Article, :id => 1 @ability.can :update, Article, :published => true @@ -234,17 +234,17 @@ expect(@ability.model_adapter(Article, :read).conditions).to eq("'t'='t'") end - it "should return appropriate sql conditions in complex case with nested joins" do + it "returns appropriate sql conditions in complex case with nested joins" do @ability.can :read, Comment, :article => { :category => { :visible => true } } expect(@ability.model_adapter(Comment, :read).conditions).to eq({ Category.table_name.to_sym => { :visible => true } }) end - it "should return appropriate sql conditions in complex case with nested joins of different depth" do + it "returns appropriate sql conditions in complex case with nested joins of different depth" do @ability.can :read, Comment, :article => { :published => true, :category => { :visible => true } } expect(@ability.model_adapter(Comment, :read).conditions).to eq({ Article.table_name.to_sym => { :published => true }, Category.table_name.to_sym => { :visible => true } }) end - it "should not forget conditions when calling with SQL string" do + it "does not forget conditions when calling with SQL string" do @ability.can :read, Article, :published => true @ability.can :read, Article, ['secret=?', false] adapter = @ability.model_adapter(Article, :read) @@ -253,35 +253,35 @@ end end - it "should have nil joins if no rules" do + it "has nil joins if no rules" do expect(@ability.model_adapter(Article, :read).joins).to be_nil end - it "should have nil joins if no nested hashes specified in conditions" do + it "has nil joins if no nested hashes specified in conditions" do @ability.can :read, Article, :published => false @ability.can :read, Article, :secret => true expect(@ability.model_adapter(Article, :read).joins).to be_nil end - it "should merge separate joins into a single array" do + it "merges separate joins into a single array" do @ability.can :read, Article, :project => { :blocked => false } @ability.can :read, Article, :company => { :admin => true } expect(@ability.model_adapter(Article, :read).joins.inspect).to orderlessly_match([:company, :project].inspect) end - it "should merge same joins into a single array" do + it "merges same joins into a single array" do @ability.can :read, Article, :project => { :blocked => false } @ability.can :read, Article, :project => { :admin => true } expect(@ability.model_adapter(Article, :read).joins).to eq([:project]) end - it "should merge nested and non-nested joins" do + it "merges nested and non-nested joins" do @ability.can :read, Article, :project => { :blocked => false } @ability.can :read, Article, :project => { :comments => { :spam => true } } expect(@ability.model_adapter(Article, :read).joins).to eq([{:project=>[:comments]}]) end - it "should merge :all conditions with other conditions" do + it "merges :all conditions with other conditions" do user = User.create! article = Article.create!(:user => user) ability = Ability.new(user) @@ -290,7 +290,7 @@ expect(Article.accessible_by(ability)).to eq([article]) end - it "should restrict articles given a MetaWhere condition" do + it "restricts articles given a MetaWhere condition" do @ability.can :read, Article, :priority.lt => 2 article1 = Article.create!(:priority => 1) article2 = Article.create!(:priority => 3) @@ -299,7 +299,7 @@ expect(@ability).to_not be_able_to(:read, article2) end - it "should merge MetaWhere and non-MetaWhere conditions" do + it "merges MetaWhere and non-MetaWhere conditions" do @ability.can :read, Article, :priority.lt => 2 @ability.can :read, Article, :priority => 1 article1 = Article.create!(:priority => 1) @@ -309,7 +309,7 @@ expect(@ability).to_not be_able_to(:read, article2) end - it "should match any MetaWhere condition" do + it "matches any MetaWhere condition" do adapter = CanCan::ModelAdapters::ActiveRecordAdapter article1 = Article.new(:priority => 1, :name => "Hello World") expect(adapter.matches_condition?(article1, :priority.eq, 1)).to be_true diff --git a/spec/cancan/model_adapters/data_mapper_adapter_spec.rb b/spec/cancan/model_adapters/data_mapper_adapter_spec.rb index bde0fc78..eac80d85 100644 --- a/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +++ b/spec/cancan/model_adapters/data_mapper_adapter_spec.rb @@ -29,36 +29,36 @@ class Comment (@ability = double).extend(CanCan::Ability) end - it "should be for only data mapper classes" do + it "is for only data mapper classes" do expect(CanCan::ModelAdapters::DataMapperAdapter).not_to be_for_class(Object) expect(CanCan::ModelAdapters::DataMapperAdapter).to be_for_class(Article) expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article)).to eq(CanCan::ModelAdapters::DataMapperAdapter) end - it "should find record" do + it "finds record" do article = Article.create expect(CanCan::ModelAdapters::DataMapperAdapter.find(Article, article.id)).to eq(article) end - it "should not fetch any records when no abilities are defined" do + it "does not fetch any records when no abilities are defined" do Article.create expect(Article.accessible_by(@ability)).to be_empty end - it "should fetch all articles when one can read all" do + it "fetches all articles when one can read all" do @ability.can :read, Article article = Article.create expect(Article.accessible_by(@ability)).to eq([article]) end - it "should fetch only the articles that are published" do + it "fetches only the articles that are published" do @ability.can :read, Article, :published => true article1 = Article.create(:published => true) article2 = Article.create(:published => false) expect(Article.accessible_by(@ability)).to eq([article1]) end - it "should fetch any articles which are published or secret" do + it "fetches any articles which are published or secret" do @ability.can :read, Article, :published => true @ability.can :read, Article, :secret => true article1 = Article.create(:published => true, :secret => false) @@ -68,7 +68,7 @@ class Comment expect(Article.accessible_by(@ability)).to eq([article1, article2, article3]) end - it "should fetch only the articles that are published and not secret" do + it "fetches only the articles that are published and not secret" do @ability.can :read, Article, :published => true @ability.cannot :read, Article, :secret => true article1 = Article.create(:published => true, :secret => false) @@ -78,14 +78,14 @@ class Comment expect(Article.accessible_by(@ability)).to eq([article1]) end - it "should only read comments for articles which are published" do + it "only reads comments for articles which are published" do @ability.can :read, Comment, :article => { :published => true } comment1 = Comment.create(:article => Article.create!(:published => true)) comment2 = Comment.create(:article => Article.create!(:published => false)) expect(Comment.accessible_by(@ability)).to eq([comment1]) end - it "should allow conditions in SQL and merge with hash conditions" do + it "allows conditions in SQL and merge with hash conditions" do @ability.can :read, Article, :published => true @ability.can :read, Article, ["secret=?", true] article1 = Article.create(:published => true, :secret => false) @@ -93,7 +93,7 @@ class Comment expect(Article.accessible_by(@ability)).to eq([article1]) end - it "should match gt comparison" do + it "matches gt comparison" do @ability.can :read, Article, :priority.gt => 3 article1 = Article.create(:priority => 4) article2 = Article.create(:priority => 3) @@ -102,7 +102,7 @@ class Comment expect(@ability).not_to be_able_to(:read, article2) end - it "should match gte comparison" do + it "matches gte comparison" do @ability.can :read, Article, :priority.gte => 3 article1 = Article.create(:priority => 4) article2 = Article.create(:priority => 3) diff --git a/spec/cancan/model_adapters/default_adapter_spec.rb b/spec/cancan/model_adapters/default_adapter_spec.rb index 27943e42..bc7f0e15 100644 --- a/spec/cancan/model_adapters/default_adapter_spec.rb +++ b/spec/cancan/model_adapters/default_adapter_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" describe CanCan::ModelAdapters::DefaultAdapter do - it "should be default for generic classes" do + it "is default for generic classes" do expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(Object)).to eq(CanCan::ModelAdapters::DefaultAdapter) end end diff --git a/spec/cancan/model_adapters/mongoid_adapter_spec.rb b/spec/cancan/model_adapters/mongoid_adapter_spec.rb index c01b6da5..1e5ee615 100644 --- a/spec/cancan/model_adapters/mongoid_adapter_spec.rb +++ b/spec/cancan/model_adapters/mongoid_adapter_spec.rb @@ -29,24 +29,24 @@ class MongoidProject end.each(&:drop) end - it "should be for only Mongoid classes" do + it "is for only Mongoid classes" do expect(CanCan::ModelAdapters::MongoidAdapter).not_to be_for_class(Object) expect(CanCan::ModelAdapters::MongoidAdapter).to be_for_class(MongoidProject) expect(CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoidProject)).to eq(CanCan::ModelAdapters::MongoidAdapter) end - it "should find record" do + it "finds record" do project = MongoidProject.create expect(CanCan::ModelAdapters::MongoidAdapter.find(MongoidProject, project.id)).to eq(project) end - it "should compare properties on mongoid documents with the conditions hash" do + it "compares properties on mongoid documents with the conditions hash" do model = MongoidProject.new @ability.can :read, MongoidProject, :id => model.id expect(@ability).to be_able_to(:read, model) end - it "should be able to read hashes when field is array" do + it "is able to read hashes when field is array" do one_to_three = MongoidProject.create(:numbers => ['one', 'two', 'three']) two_to_five = MongoidProject.create(:numbers => ['two', 'three', 'four', 'five']) @@ -55,7 +55,7 @@ class MongoidProject expect(@ability).not_to be_able_to(:foo, two_to_five) end - it "should return [] when no ability is defined so no records are found" do + it "returns [] when no ability is defined so no records are found" do MongoidProject.create(:title => 'Sir') MongoidProject.create(:title => 'Lord') MongoidProject.create(:title => 'Dude') @@ -63,7 +63,7 @@ class MongoidProject expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([]) end - it "should return the correct records based on the defined ability" do + it "returns the correct records based on the defined ability" do @ability.can :read, MongoidProject, :title => "Sir" sir = MongoidProject.create(:title => 'Sir') lord = MongoidProject.create(:title => 'Lord') @@ -72,7 +72,7 @@ class MongoidProject expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir]) end - it "should return the correct records when a mix of can and cannot rules in defined ability" do + it "returns the correct records when a mix of can and cannot rules in defined ability" do @ability.can :manage, MongoidProject, :title => 'Sir' @ability.cannot :destroy, MongoidProject @@ -83,7 +83,7 @@ class MongoidProject expect(MongoidProject.accessible_by(@ability, :destroy).entries).to eq([sir]) end - it "should be able to mix empty conditions and hashes" do + it "is able to mix empty conditions and hashes" do @ability.can :read, MongoidProject @ability.can :read, MongoidProject, :title => 'Sir' sir = MongoidProject.create(:title => 'Sir') @@ -92,7 +92,7 @@ class MongoidProject expect(MongoidProject.accessible_by(@ability, :read).count).to eq(2) end - it "should return everything when the defined ability is manage all" do + it "returns everything when the defined ability is access all" do @ability.can :manage, :all sir = MongoidProject.create(:title => 'Sir') lord = MongoidProject.create(:title => 'Lord') @@ -101,7 +101,7 @@ class MongoidProject expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([sir, lord, dude]) end - it "should allow a scope for conditions" do + it "allows a scope for conditions" do @ability.can :read, MongoidProject, MongoidProject.where(:title => 'Sir') sir = MongoidProject.create(:title => 'Sir') lord = MongoidProject.create(:title => 'Lord') @@ -111,7 +111,7 @@ class MongoidProject end describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do - it "should handle :field.in" do + it "handles :field.in" do obj = MongoidProject.create(:title => 'Sir') @ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"] expect(@ability.can?(:read, obj)).to eq(true) @@ -137,7 +137,7 @@ class MongoidProject end end - it "should handle :field.nin" do + it "handles :field.nin" do obj = MongoidProject.create(:title => 'Sir') @ability.can :read, MongoidProject, :title.nin => ["Lord", "Madam"] expect(@ability.can?(:read, obj)).to eq(true) @@ -147,7 +147,7 @@ class MongoidProject expect(@ability.can?(:read, obj2)).to be_false end - it "should handle :field.size" do + it "handles :field.size" do obj = MongoidProject.create(:titles => ['Palatin', 'Margrave']) @ability.can :read, MongoidProject, :titles.size => 2 expect(@ability.can?(:read, obj)).to eq(true) @@ -157,7 +157,7 @@ class MongoidProject expect(@ability.can?(:read, obj2)).to be_false end - it "should handle :field.exists" do + it "handles :field.exists" do obj = MongoidProject.create(:titles => ['Palatin', 'Margrave']) @ability.can :read, MongoidProject, :titles.exists => true expect(@ability.can?(:read, obj)).to eq(true) @@ -167,7 +167,7 @@ class MongoidProject expect(@ability.can?(:read, obj2)).to be_false end - it "should handle :field.gt" do + it "handles :field.gt" do obj = MongoidProject.create(:age => 50) @ability.can :read, MongoidProject, :age.gt => 45 expect(@ability.can?(:read, obj)).to eq(true) @@ -177,7 +177,7 @@ class MongoidProject expect(@ability.can?(:read, obj2)).to be_false end - it "should handle instance not saved to database" do + it "handles instance not saved to database" do obj = MongoidProject.new(:title => 'Sir') @ability.can :read, MongoidProject, :title.in => ["Sir", "Madam"] expect(@ability.can?(:read, obj)).to eq(true) @@ -190,13 +190,13 @@ class MongoidProject end end - it "should call where with matching ability conditions" do + it "calls where with matching ability conditions" do obj = MongoidProject.create(:foo => {:bar => 1}) @ability.can :read, MongoidProject, :foo => {:bar => 1} expect(MongoidProject.accessible_by(@ability, :read).entries.first).to eq(obj) end - it "should exclude from the result if set to cannot" do + it "excludes from the result if set to cannot" do obj = MongoidProject.create(:bar => 1) obj2 = MongoidProject.create(:bar => 2) @ability.can :read, MongoidProject @@ -204,7 +204,7 @@ class MongoidProject expect(MongoidProject.accessible_by(@ability, :read).entries).to eq([obj]) end - it "should combine the rules" do + it "combines the rules" do obj = MongoidProject.create(:bar => 1) obj2 = MongoidProject.create(:bar => 2) obj3 = MongoidProject.create(:bar => 3) @@ -213,7 +213,7 @@ class MongoidProject expect(MongoidProject.accessible_by(@ability, :read).entries).to match_array([obj, obj2]) end - it "should not allow to fetch records when ability with just block present" do + it "does not allow to fetch records when ability with just block present" do @ability.can :read, MongoidProject do false end diff --git a/spec/cancan/rule_spec.rb b/spec/cancan/rule_spec.rb index 643b65ad..91dab530 100644 --- a/spec/cancan/rule_spec.rb +++ b/spec/cancan/rule_spec.rb @@ -8,44 +8,44 @@ @rule = CanCan::Rule.new(true, :read, Integer, @conditions, nil) end - it "should return no association joins if none exist" do + it "returns no association joins if none exist" do expect(@rule.associations_hash).to eq({}) end - it "should return no association for joins if just attributes" do + it "returns no association for joins if just attributes" do @conditions[:foo] = :bar expect(@rule.associations_hash).to eq({}) end - it "should return single association for joins" do + it "returns single association for joins" do @conditions[:foo] = {:bar => 1} expect(@rule.associations_hash).to eq({:foo => {}}) end - it "should return multiple associations for joins" do + it "returns multiple associations for joins" do @conditions[:foo] = {:bar => 1} @conditions[:test] = {1 => 2} expect(@rule.associations_hash).to eq({:foo => {}, :test => {}}) end - it "should return nested associations for joins" do + it "returns nested associations for joins" do @conditions[:foo] = {:bar => {1 => 2}} expect(@rule.associations_hash).to eq({:foo => {:bar => {}}}) end - it "should return no association joins if conditions is nil" do + it "returns no association joins if conditions is nil" do rule = CanCan::Rule.new(true, :read, Integer, nil, nil) expect(rule.associations_hash).to eq({}) end - it "should not be mergeable if conditions are not simple hashes" do + it "is not mergeable if conditions are not simple hashes" do meta_where = OpenStruct.new(:name => 'metawhere', :column => 'test') @conditions[meta_where] = :bar expect(@rule).to be_unmergeable end - it "should be mergeable if conditions is an empty hash" do + it "is not mergeable if conditions is an empty hash" do @conditions = {} expect(@rule).to_not be_unmergeable end From 04acbdc00a42a94dc0b4237c3721a1ffaea7dc53 Mon Sep 17 00:00:00 2001 From: Eric Chapweske Date: Thu, 22 Aug 2013 14:18:39 -0700 Subject: [PATCH 17/22] Reduce object allocations --- lib/cancan/ability.rb | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/lib/cancan/ability.rb b/lib/cancan/ability.rb index 2a3dc808..79590737 100644 --- a/lib/cancan/ability.rb +++ b/lib/cancan/ability.rb @@ -256,9 +256,20 @@ def unauthorized_message_keys(action, subject) # This should be called before "matches?" and other checking methods since they # rely on the actions to be expanded. def expand_actions(actions) - actions.map do |action| - aliased_actions[action] ? [action, *expand_actions(aliased_actions[action])] : action - end.flatten + expanded_actions[actions] ||= begin + expanded = [] + actions.each do |action| + expanded << action + if aliases = aliased_actions[action] + expanded += expand_actions(aliases) + end + end + expanded + end + end + + def expanded_actions + @expanded_actions ||= {} end # Given an action, it will try to find all of the actions which are aliased to it. @@ -278,10 +289,12 @@ def rules # Returns an array of Rule instances which match the action and subject # This does not take into consideration any hash conditions or block statements def relevant_rules(action, subject) - rules.reverse.select do |rule| + relevant = rules.select do |rule| rule.expanded_actions = expand_actions(rule.actions) rule.relevant? action, subject end + relevant.reverse! + relevant end def relevant_rules_for_match(action, subject) From 3c97fb385c5ccb8eef9124041392c945ad138fb3 Mon Sep 17 00:00:00 2001 From: Bryan Rite Date: Mon, 27 Jan 2014 13:12:33 -0800 Subject: [PATCH 18/22] Fixes to specs for spec update. --- spec/cancan/controller_resource_spec.rb | 2 +- spec/cancan/model_adapters/active_record_adapter_spec.rb | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/cancan/controller_resource_spec.rb b/spec/cancan/controller_resource_spec.rb index e85e75e4..2b88dddb 100644 --- a/spec/cancan/controller_resource_spec.rb +++ b/spec/cancan/controller_resource_spec.rb @@ -408,7 +408,7 @@ class Section it "should id param return nil if param is nil" do @params.merge!(:action => "show", :the_project => nil) resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project) - resource.send(:id_param).class.should == NilClass + expect(resource.send(:id_param)).to be_nil end it "loads resource using custom find_by attribute" do diff --git a/spec/cancan/model_adapters/active_record_adapter_spec.rb b/spec/cancan/model_adapters/active_record_adapter_spec.rb index 8ea9a601..7b4fecbd 100644 --- a/spec/cancan/model_adapters/active_record_adapter_spec.rb +++ b/spec/cancan/model_adapters/active_record_adapter_spec.rb @@ -119,7 +119,7 @@ article1 = Article.create!(:published => true) article2 = Article.create!(:published => false) article3 = Article.create!(:published => false, :category => Category.create!(:visible => true)) - Article.accessible_by(@ability).should == [article1, article3] + expect(Article.accessible_by(@ability)).to eq([article1, article3]) end it "should only read categories once even if they have multiple articles" do @@ -128,7 +128,7 @@ category = Category.create! Article.create!(:published => true, :category => category) Article.create!(:published => true, :category => category) - Category.accessible_by(@ability).should == [category] + expect(Category.accessible_by(@ability)).to eq([category]) end it "only reads comments for visible categories through articles" do @@ -350,8 +350,7 @@ article.secret == true end - # Ensure the ActiveRecord::Relation condition does not trigger a count query - stub(relation).count { fail 'Unexpected scope execution.' } + relation.stub(:count).and_raise('Unexpected scope execution.') expect { @ability.can? :read, Article }.not_to raise_error end From 23b2ed6797f4db39f185cc07e3e74e0f43297c37 Mon Sep 17 00:00:00 2001 From: Bryan Rite Date: Mon, 27 Jan 2014 16:05:16 -0800 Subject: [PATCH 19/22] Support for strong_parameters --- CHANGELOG.rdoc | 4 ++ README.rdoc | 36 ++++++++++++++++-- lib/cancan/controller_resource.rb | 21 ++++++++++- spec/cancan/controller_resource_spec.rb | 50 +++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 4b7ecdcf..8c355db6 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,3 +1,7 @@ +Master + +* Adds support for strong_parameters (bryanrite) + 1.6.10 (May 7, 2013) * fix matches_conditons_hash for string values on 1.8 (thanks rrosen) diff --git a/README.rdoc b/README.rdoc index 9b3baf8d..a65ae004 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,6 +1,6 @@ = CanCan -{Gem Version}[http://badge.fury.io/rb/cancan] -{}[http://travis-ci.org/ryanb/cancan] +{Gem Version}[http://badge.fury.io/rb/cancan] +{}[http://travis-ci.org/ryanb/cancan] {}[https://codeclimate.com/github/ryanb/cancan] Wiki[https://github.com/ryanb/cancan/wiki] | RDocs[http://rdoc.info/projects/ryanb/cancan] | Screencast[http://railscasts.com/episodes/192-authorization-with-cancan] @@ -34,7 +34,7 @@ User permissions are defined in an +Ability+ class. CanCan 1.5 includes a Rails rails g cancan:ability -In Rails 2.3, just add a new class in `app/models/ability.rb` with the following contents: +In Rails 2.3, just add a new class in app/models/ability.rb with the following contents: class Ability include CanCan::Ability @@ -76,6 +76,36 @@ Setting this for every action can be tedious, therefore the +load_and_authorize_ See {Authorizing Controller Actions}[https://github.com/ryanb/cancan/wiki/authorizing-controller-actions] for more information. +==== Strong Parameters + +When using strong_parameters or Rails 4+, you have to sanitize inputs before saving the record, in actions such as :create and :update. + +By default, CanCan will try to sanitize the input on :create and :update routes by seeing if your controller will respond to the following methods (in order): + +* create_params or update_params (depending on the action you are performing) +* _params such as article_params (this is the default convention in rails for naming your param method) +* resource_params (a generically named method you could specify in each controller) + +Additionally, load_and_authorize_resource can now take a param_method option to specify a custom method in the controller to run to sanitize input. + + class ArticlesController < ApplicationController + load_and_authorize_resource param_method: :my_sanitizer + + def create + if @article.save + # hurray + else + render :new + end + end + + private + + def my_sanitizer + params.require(:article).permit(:name) + end + end + === 3. Handle Unauthorized Access If the user authorization fails, a CanCan::AccessDenied exception will be raised. You can catch this and modify its behavior in the +ApplicationController+. diff --git a/lib/cancan/controller_resource.rb b/lib/cancan/controller_resource.rb index 702fbcfb..2b630b04 100644 --- a/lib/cancan/controller_resource.rb +++ b/lib/cancan/controller_resource.rb @@ -214,7 +214,9 @@ def name end def resource_params - if @options[:class] + if param_actions.include?(@params[:action].to_sym) && params_method.present? + return @controller.send(params_method) + elsif @options[:class] params_key = extract_key(@options[:class]) return @params[params_key] if @params[params_key] end @@ -226,6 +228,19 @@ def resource_params_by_namespaced_name @params[extract_key(namespaced_name)] end + def params_method + params_methods.each do |method| + return method if @controller.respond_to?(method, true) + end + nil + end + + def params_methods + methods = ["#{@params[:action]}_params".to_sym, "#{name}_params".to_sym, :resource_params] + methods.unshift(@options[:param_method]) if @options[:param_method].present? + methods + end + def namespace @params[:controller].split(/::|\//)[0..-2] end @@ -252,6 +267,10 @@ def new_actions [:new, :create] + [@options[:new]].flatten end + def param_actions + [:create, :update] + end + private def extract_key(value) diff --git a/spec/cancan/controller_resource_spec.rb b/spec/cancan/controller_resource_spec.rb index 03f16bfb..a77a34b1 100644 --- a/spec/cancan/controller_resource_spec.rb +++ b/spec/cancan/controller_resource_spec.rb @@ -488,4 +488,54 @@ class Section lambda { resource.load_and_authorize_resource }.should_not raise_error @controller.instance_variable_get(:@project).should be_nil end + + context "with a strong parameters method" do + + it "only calls the santitize method with actions matching param_actions" do + @params.merge!(:controller => "project", :action => "update") + @controller.stub(:resource_params).and_return(resource: 'params') + resource = CanCan::ControllerResource.new(@controller) + resource.stub(param_actions: [:create]) + + @controller.should_not_receive(:send).with(:resource_params) + resource.send("resource_params") + end + + it "uses the specified option for santitizing input" do + @params.merge!(:controller => "project", :action => "create") + @controller.stub(:resource_params).and_return(resource: 'params') + @controller.stub(:project_params).and_return(model: 'params') + @controller.stub(:create_params).and_return(create: 'params') + @controller.stub(:custom_params).and_return(custom: 'params') + resource = CanCan::ControllerResource.new(@controller, {param_method: :custom_params}) + expect(resource.send("resource_params")).to eq(custom: 'params') + end + + it "prefers to use the create_params method for santitizing input" do + @params.merge!(:controller => "project", :action => "create") + @controller.stub(:resource_params).and_return(resource: 'params') + @controller.stub(:project_params).and_return(model: 'params') + @controller.stub(:create_params).and_return(create: 'params') + @controller.stub(:custom_params).and_return(custom: 'params') + resource = CanCan::ControllerResource.new(@controller) + expect(resource.send("resource_params")).to eq(create: 'params') + end + + it "prefers to use the _params method for santitizing input if create is not found" do + @params.merge!(:controller => "project", :action => "create") + @controller.stub(:resource_params).and_return(resource: 'params') + @controller.stub(:project_params).and_return(model: 'params') + @controller.stub(:custom_params).and_return(custom: 'params') + resource = CanCan::ControllerResource.new(@controller) + expect(resource.send("resource_params")).to eq(model: 'params') + end + + it "prefers to use the resource_params method for santitizing input if create or model is not found" do + @params.merge!(:controller => "project", :action => "create") + @controller.stub(:resource_params).and_return(resource: 'params') + @controller.stub(:custom_params).and_return(custom: 'params') + resource = CanCan::ControllerResource.new(@controller) + expect(resource.send("resource_params")).to eq(resource: 'params') + end + end end From d76b2b09ae48269340a9a564539cfd86903ab17d Mon Sep 17 00:00:00 2001 From: Bryan Rite Date: Mon, 27 Jan 2014 16:58:16 -0800 Subject: [PATCH 20/22] Run against modern rubies. --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b31a69b4..82e41fea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ rvm: - - 1.8.7 + - 1.9.2 - 1.9.3 - 2.0.0 + - 2.1.0 - ree notifications: recipients: From 8e70203e63a295760351bddb09b4a724db162961 Mon Sep 17 00:00:00 2001 From: Bryan Rite Date: Mon, 27 Jan 2014 17:47:42 -0800 Subject: [PATCH 21/22] Add back in 1.8.7 support. --- .travis.yml | 1 + spec/cancan/controller_resource_spec.rb | 48 ++++++++++++++----------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/.travis.yml b/.travis.yml index 82e41fea..50182cf3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ rvm: + - 1.8.7 - 1.9.2 - 1.9.3 - 2.0.0 diff --git a/spec/cancan/controller_resource_spec.rb b/spec/cancan/controller_resource_spec.rb index 1e3223c9..a4ddacfa 100644 --- a/spec/cancan/controller_resource_spec.rb +++ b/spec/cancan/controller_resource_spec.rb @@ -497,9 +497,9 @@ class Section it "only calls the santitize method with actions matching param_actions" do @params.merge!(:controller => "project", :action => "update") - @controller.stub(:resource_params).and_return(resource: 'params') + @controller.stub(:resource_params).and_return(:resource => 'params') resource = CanCan::ControllerResource.new(@controller) - resource.stub(param_actions: [:create]) + resource.stub(:param_actions => [:create]) @controller.should_not_receive(:send).with(:resource_params) resource.send("resource_params") @@ -507,39 +507,47 @@ class Section it "uses the specified option for santitizing input" do @params.merge!(:controller => "project", :action => "create") - @controller.stub(:resource_params).and_return(resource: 'params') - @controller.stub(:project_params).and_return(model: 'params') - @controller.stub(:create_params).and_return(create: 'params') - @controller.stub(:custom_params).and_return(custom: 'params') - resource = CanCan::ControllerResource.new(@controller, {param_method: :custom_params}) - expect(resource.send("resource_params")).to eq(custom: 'params') + @controller.stub(:resource_params).and_return(:resource => 'params') + @controller.stub(:project_params).and_return(:model => 'params') + @controller.stub(:create_params).and_return(:create => 'params') + @controller.stub(:custom_params).and_return(:custom => 'params') + resource = CanCan::ControllerResource.new(@controller, {:param_method => :custom_params}) + expect(resource.send("resource_params")).to eq(:custom => 'params') end it "prefers to use the create_params method for santitizing input" do @params.merge!(:controller => "project", :action => "create") - @controller.stub(:resource_params).and_return(resource: 'params') - @controller.stub(:project_params).and_return(model: 'params') - @controller.stub(:create_params).and_return(create: 'params') - @controller.stub(:custom_params).and_return(custom: 'params') + @controller.stub(:resource_params).and_return(:resource => 'params') + @controller.stub(:project_params).and_return(:model => 'params') + @controller.stub(:create_params).and_return(:create => 'params') + @controller.stub(:custom_params).and_return(:custom => 'params') resource = CanCan::ControllerResource.new(@controller) - expect(resource.send("resource_params")).to eq(create: 'params') + expect(resource.send("resource_params")).to eq(:create => 'params') + end + + it "uses the proper action param based on the action" do + @params.merge!(:controller => "project", :action => "update") + @controller.stub(:create_params).and_return(:create => 'params') + @controller.stub(:update_params).and_return(:update => 'params') + resource = CanCan::ControllerResource.new(@controller) + expect(resource.send("resource_params")).to eq(:update => 'params') end it "prefers to use the _params method for santitizing input if create is not found" do @params.merge!(:controller => "project", :action => "create") - @controller.stub(:resource_params).and_return(resource: 'params') - @controller.stub(:project_params).and_return(model: 'params') - @controller.stub(:custom_params).and_return(custom: 'params') + @controller.stub(:resource_params).and_return(:resource => 'params') + @controller.stub(:project_params).and_return(:model => 'params') + @controller.stub(:custom_params).and_return(:custom => 'params') resource = CanCan::ControllerResource.new(@controller) - expect(resource.send("resource_params")).to eq(model: 'params') + expect(resource.send("resource_params")).to eq(:model => 'params') end it "prefers to use the resource_params method for santitizing input if create or model is not found" do @params.merge!(:controller => "project", :action => "create") - @controller.stub(:resource_params).and_return(resource: 'params') - @controller.stub(:custom_params).and_return(custom: 'params') + @controller.stub(:resource_params).and_return(:resource => 'params') + @controller.stub(:custom_params).and_return(:custom => 'params') resource = CanCan::ControllerResource.new(@controller) - expect(resource.send("resource_params")).to eq(resource: 'params') + expect(resource.send("resource_params")).to eq(:resource => 'params') end end end From 014f51307fa34d42602e71fa86724f532504f6a2 Mon Sep 17 00:00:00 2001 From: Bryan Rite Date: Wed, 29 Jan 2014 09:57:45 -0800 Subject: [PATCH 22/22] add jruby and rubinus to travis --- .travis.yml | 5 +++++ Gemfile | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 50182cf3..d1237afa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,11 @@ rvm: - 2.0.0 - 2.1.0 - ree + - jruby + - rbx +matrix: + allow_failures: + - rvm: rbx notifications: recipients: - graf.otodrakula@gmail.com diff --git a/Gemfile b/Gemfile index 2f446c95..e0bb0f63 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,10 @@ source "https://rubygems.org" case ENV["MODEL_ADAPTER"] when nil, "active_record" - gem "sqlite3" + # Sqlite for CRuby, Rubinius, including Windows and RubyInstaller + gem "sqlite3", :platform => [:ruby, :mswin, :mingw] + # Sqlite for JRuby + gem 'activerecord-jdbcsqlite3-adapter', :platform => :jruby gem "activerecord", '~> 3.0.9', :require => "active_record" gem "with_model", "~> 0.2.5" gem "meta_where"