diff --git a/.rbenv-version b/.rbenv-version new file mode 100644 index 0000000..36b4444 --- /dev/null +++ b/.rbenv-version @@ -0,0 +1 @@ +1.9.3-p194 \ No newline at end of file diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 367a91e..9496deb 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,3 +1,48 @@ +1.6.8 (June 25, 2012) + +* improved support for namespaced controllers and models + +* pass :if and :unless options for load and authorize resource (thanks mauriciozaffari) + +* Travis CI badge (thanks plentz) + +* adding Ability#merge for combining multiple abilities (thanks rogercampos) + +* support for multiple MetaWhere rules (thanks andhapp) + +* various fixes for DataMapper, Mongoid, and Inherited Resource integration + +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.7...1.6.8] + + +1.6.7 (October 4, 2011) + +* fixing nested resource problem caused by namespace addition - issue #482 + +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.6...1.6.7] + + +1.6.6 (September 28, 2011) + +* correct "return cant jump across threads" error when using check_authorization (thanks codeprimate) - issues #463, #469 + +* fixing tests in development by specifying with_model version (thanks kirkconnell) - issue #476 + +* added travis.yml file for TravisCI support (thanks bai) - issue #427 + +* better support for namespaced models (thanks whilefalse) - issues #424 + +* adding :id_param option to load_and_authorize_resource (thanks skhisma) - issue #425 + +* make default unauthorized message translatable text (thanks nhocki) - issue #409 + +* improving DataMapper behavior (thanks psanford, maxsum-corin) - issue #410, #373 + +* allow :find_by option to be full find method name - issue #335 + +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.5...1.6.6] + + 1.6.5 (May 18, 2011) * pass action and subject through AccessDenied exception when :through isn't found - issue #366 @@ -14,12 +59,15 @@ * improve scope merging - issue #328 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.4...1.6.5] 1.6.4 (March 29, 2011) * Fixed mongoid 'or' error - see issue #322 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.3...1.6.4] + 1.6.3 (March 25, 2011) @@ -27,11 +75,15 @@ * Return subject passed to authorize! - see issue #314 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.2...1.6.3] + 1.6.2 (March 18, 2011) * Fixed instance loading when :singleton option is used - see issue #310 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.1...1.6.2] + 1.6.1 (March 15, 2011) @@ -41,6 +93,8 @@ * Reverted Inherited Resources "collection" override since it doesn't seem to be working - see issue #305 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.0...1.6.1] + 1.6.0 (March 11, 2011) @@ -62,6 +116,8 @@ * Raise an exception when trying to make a Ability condition with both a hash of conditions and a block - see issue #269 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.5.1...1.6.0] + 1.5.1 (January 20, 2011) @@ -69,6 +125,8 @@ * Improving Mongoid support for multiple can and cannot definitions (thanks stellard) - see issue #239 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.5.0...1.5.1] + 1.5.0 (January 11, 2011) @@ -90,6 +148,8 @@ * Internal: added .rvmrc to auto-switch to 1.8.7 with gemset - see issue #231 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.4.1...1.5.0] + 1.4.1 (November 12, 2010) @@ -103,6 +163,8 @@ * Fix odd behavior when "cache_classes = false" (thanks mphalliday) - see issue #174 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.4.0...1.4.1] + 1.4.0 (October 5, 2010) @@ -142,11 +204,15 @@ * No longer calling block in +can+ definition when checking on class - see issue #116 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.4...1.4.0] + 1.3.4 (August 31, 2010) * Don't stop at +cannot+ with hash conditions when checking class (thanks tamoya) - see issue #131 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.3...1.3.4] + 1.3.3 (August 20, 2010) @@ -154,16 +220,22 @@ * Pluralize nested associations for conditions in accessible_by (thanks mlooney) - see issue #123 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.2...1.3.3] + 1.3.2 (August 7, 2010) * Fixing slice error when passing in custom resource name - see issue #112 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.1...1.3.2] + 1.3.1 (August 6, 2010) * Fixing protected sanitize_sql error - see issue #111 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.0...1.3.1] + 1.3.0 (August 6, 2010) @@ -191,6 +263,8 @@ * Supporting deeply nested aliases - see issue #98 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.2.0...1.3.0] + 1.2.0 (July 16, 2010) @@ -206,11 +280,15 @@ * Adding joins clause to accessible_by when conditions are across associations +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.1.1...1.2.0] + 1.1.1 (April 17, 2010) * Fixing behavior in Rails 3 by properly initializing ResourceAuthorization +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.1...1.1.1] + 1.1.0 (April 17, 2010) @@ -234,6 +312,8 @@ * Support additional arguments to can? which get passed to the block - see issue #48 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.0.2...1.1] + 1.0.2 (Dec 30, 2009) @@ -243,6 +323,8 @@ * Adding custom message argument to unauthorized! method (thanks tjwallace) - see issue #18 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.0.1...1.0.2] + 1.0.1 (Dec 14, 2009) @@ -250,6 +332,8 @@ * Don't fetch parent of nested resource if *_id parameter is missing so it works with shallow nested routes - see issue #14 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.0.0...1.0.1] + 1.0.0 (Dec 13, 2009) @@ -265,6 +349,8 @@ * BACKWARDS INCOMPATIBLE: turning load and authorize resource methods into class methods which set up the before filter so they can accept additional arguments. +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/0.2.1...1.0.0] + 0.2.1 (Nov 26, 2009) @@ -274,6 +360,8 @@ * support custom objects (usually symbols) in can definition - see issue #8 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/0.2.0...0.2.1] + 0.2.0 (Nov 17, 2009) @@ -285,6 +373,8 @@ * BACKWARDS INCOMPATIBLE: use Ability#initialize instead of 'prepare' to set up abilities - see issue #4 +* {see the full list of changes}[https://github.com/ryanb/cancan/compare/0.1.0...0.2.0] + 0.1.0 (Nov 16, 2009) diff --git a/README.rdoc b/README.rdoc index e72fb29..1a9c803 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1,4 +1,4 @@ -= CanCan += CanCan {}[http://travis-ci.org/ryanb/cancan] This is the branch for CanCan 2.0 which is in very early development. For a stable release please check out the {master branch}[https://github.com/ryanb/cancan] diff --git a/lib/cancan/ability.rb b/lib/cancan/ability.rb index 915a0ca..c2b9a9f 100644 --- a/lib/cancan/ability.rb +++ b/lib/cancan/ability.rb @@ -254,6 +254,13 @@ module CanCan @fully_authorized << [action.to_sym, subject.to_sym] end + def merge(ability) + ability.send(:rules).each do |rule| + rules << rule.dup + end + self + end + private def unauthorized_message_keys(action, subject) diff --git a/lib/cancan/controller_additions.rb b/lib/cancan/controller_additions.rb index 19614b4..9dcf3a1 100644 --- a/lib/cancan/controller_additions.rb +++ b/lib/cancan/controller_additions.rb @@ -94,7 +94,7 @@ module CanCan # [:+find_by+] # Find using a different attribute other than id. For example. # - # load_resource :find_by => :permalink # will use find_by_permlink!(params[:id]) + # load_resource :find_by => :permalink # will use find_by_permalink!(params[:id]) # # [:+collection+] # Specify which actions are resource collection actions in addition to :+index+. This @@ -152,6 +152,9 @@ module CanCan # [:+except+] # Does not apply before filter to given actions. # + # [:+singleton+] + # Pass +true+ if this is a singleton resource through a +has_one+ association. + # # [:+parent+] # True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource # name is given which does not match the controller. @@ -382,7 +385,7 @@ module CanCan end end -if defined? ActionController +if defined? ActionController::Base ActionController::Base.class_eval do include CanCan::ControllerAdditions end diff --git a/lib/cancan/controller_resource.rb b/lib/cancan/controller_resource.rb index 355ebb6..39cfacc 100644 --- a/lib/cancan/controller_resource.rb +++ b/lib/cancan/controller_resource.rb @@ -6,8 +6,8 @@ module CanCan options = args.extract_options!.merge(behavior) resource_name = args.first before_filter_method = options.delete(:prepend) ? :prepend_before_filter : :before_filter - controller_class.send(before_filter_method, options.slice(:only, :except)) do |controller| - controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except)).process + controller_class.send(before_filter_method, options.slice(:only, :except, :if, :unless)) do |controller| + controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except, :if, :unless)).process end end @@ -81,6 +81,10 @@ module CanCan def build_resource resource = resource_base.new(resource_params || {}) + assign_attributes(resource) + end + + def assign_attributes(resource) resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource initial_attributes.each do |attr_name, value| resource.send("#{attr_name}=", value) @@ -225,12 +229,19 @@ module CanCan end def resource_params - # since Rails includes the namespace in the params sent by the form (issue #349) - @params[namespaced_name.to_s.underscore.gsub("/", "_")] + if @options[:class] + @params[@options[:class].to_s.underscore.gsub('/', '_')] + else + @params[namespaced_name.to_s.underscore.gsub("/", "_")] + end + end + + def namespace + @params[:controller].split("::")[0..-2] end def namespaced_name - (@name || @params[:controller].sub("Controller", "")).singularize.camelize.constantize + [namespace, name.camelize].join('::').singularize.camelize.constantize rescue NameError name end diff --git a/lib/cancan/inherited_resource.rb b/lib/cancan/inherited_resource.rb index 81bca5b..61bd333 100644 --- a/lib/cancan/inherited_resource.rb +++ b/lib/cancan/inherited_resource.rb @@ -6,7 +6,8 @@ module CanCan @controller.send :association_chain @controller.instance_variable_get("@#{instance_name}") elsif new_actions.include? @params[:action].to_sym - @controller.send :build_resource + resource = @controller.send :build_resource + assign_attributes(resource) else @controller.send :resource end diff --git a/lib/cancan/model_adapters/active_record_adapter.rb b/lib/cancan/model_adapters/active_record_adapter.rb index a98cae2..f20da17 100644 --- a/lib/cancan/model_adapters/active_record_adapter.rb +++ b/lib/cancan/model_adapters/active_record_adapter.rb @@ -89,7 +89,12 @@ module CanCan if override_scope @model_class.scoped.merge(override_scope) elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins) - @model_class.where(conditions).joins(joins) + mergeable_conditions = @rules.select {|rule| rule.unmergeable? }.blank? + if mergeable_conditions + @model_class.where(conditions).joins(joins) + else + @model_class.where(*(@rules.map(&:conditions))).joins(joins) + end else @model_class.scoped(:conditions => conditions, :joins => joins) end diff --git a/lib/cancan/model_adapters/mongoid_adapter.rb b/lib/cancan/model_adapters/mongoid_adapter.rb index 7993252..6c7f37d 100644 --- a/lib/cancan/model_adapters/mongoid_adapter.rb +++ b/lib/cancan/model_adapters/mongoid_adapter.rb @@ -30,8 +30,9 @@ module CanCan else # we only need to process can rules if # there are no rules with empty conditions - rules = @rules.reject { |rule| rule.conditions.empty? } + rules = @rules.reject { |rule| rule.conditions.empty? && rule.base_behavior } process_can_rules = @rules.count == rules.count + rules.inject(@model_class.all) do |records, rule| if process_can_rules && rule.base_behavior records.or rule.conditions diff --git a/lib/cancan/rule.rb b/lib/cancan/rule.rb index 097ce02..a3c86ef 100644 --- a/lib/cancan/rule.rb +++ b/lib/cancan/rule.rb @@ -63,6 +63,10 @@ module CanCan @block || conditions? end + def unmergeable? + @conditions.respond_to?(:keys) && (! @conditions.keys.first.kind_of? Symbol) + end + def associations_hash(conditions = @conditions) hash = {} conditions.map do |name, value| @@ -139,7 +143,7 @@ module CanCan else attribute && matches_conditions_hash?(attribute, value) end - elsif value.kind_of?(Array) || value.kind_of?(Range) + elsif value.kind_of?(Enumerable) value.include? attribute else attribute == value @@ -151,7 +155,7 @@ module CanCan end def nested_subject_matches_conditions?(subject_hash) - parent, child = subject_hash.shift + parent, child = subject_hash.first matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {}) end @@ -168,7 +172,7 @@ module CanCan end def model_adapter(subject) - ModelAdapters::AbstractAdapter.adapter_class(subject_object?(subject) ? subject.class : subject) + CanCan::ModelAdapters::AbstractAdapter.adapter_class(subject_object?(subject) ? subject.class : subject) end end end diff --git a/spec/cancan/ability_spec.rb b/spec/cancan/ability_spec.rb index 44e2480..7204678 100644 --- a/spec/cancan/ability_spec.rb +++ b/spec/cancan/ability_spec.rb @@ -290,6 +290,16 @@ describe CanCan::Ability do @ability.should be_fully_authorized(:update, :ranges) end + it "should accept a set as a condition value" do + object_with_foo_2 = Object.new + object_with_foo_2.should_receive(:foo) { 2 } + object_with_foo_3 = Object.new + object_with_foo_3.should_receive(:foo) { 3 } + @ability.can :read, :objects, :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 + end + it "does not match subjects return nil for methods that must match nested a nested conditions hash" do object_with_foo = Object.new object_with_foo.should_receive(:foo) { :bar } @@ -353,7 +363,6 @@ describe CanCan::Ability do @ability.can?(:update, :books, :author).should be_false end - # Hash Association it "checks permission through association when hash is passed as subject" do @@ -363,6 +372,15 @@ describe CanCan::Ability do @ability.can?(:read, 123 => :books).should be_true end + it "checks permissions on association hash with multiple rules" do + @ability.can :read, :books, :range => {:begin => 3} + @ability.can :read, :books, :range => {:end => 6} + @ability.can?(:read, (1..4) => :books).should be_false + @ability.can?(:read, (3..5) => :books).should be_true + @ability.can?(:read, (1..6) => :books).should be_true + @ability.can?(:read, 123 => :books).should be_true + end + it "checks ability on hash subclass" do class Container < Hash; end @ability.can :read, :containers @@ -509,4 +527,15 @@ describe CanCan::Ability do # @ability.unauthorized_message(:update, ArgumentError).should == "update argument error" end end + + it "merges the rules from another ability" do + @ability.can :use, :tools + another_ability = Object.new + another_ability.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 + end end diff --git a/spec/cancan/controller_additions_spec.rb b/spec/cancan/controller_additions_spec.rb index 823a0fe..4b9e326 100644 --- a/spec/cancan/controller_additions_spec.rb +++ b/spec/cancan/controller_additions_spec.rb @@ -32,7 +32,7 @@ describe CanCan::ControllerAdditions do @controller.cannot?(:foo, :bar).should be_true end - it "load_and_authorize_resource should setup a before filter which passes call to ControllerResource" do + it "load_and_authorize_resource adds a before filter which passes call to ControllerResource" do controller_resource = double("controller_resource") controller_resource.should_receive(:process) CanCan::ControllerResource.stub(:new).with(@controller, nil, :load => true, :authorize => true, :foo => :bar) { controller_resource } @@ -40,7 +40,7 @@ describe CanCan::ControllerAdditions do @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 passes first argument as the resource name" do controller_resource = double("controller_resource") controller_resource.should_receive(:process) CanCan::ControllerResource.stub(:new).with(@controller, :project, :load => true, :authorize => true, :foo => :bar) { controller_resource } @@ -48,7 +48,15 @@ describe CanCan::ControllerAdditions do @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 passes :only, :except, :if, :unless options to before filter" do + controller_resource = double("controller_resource") + controller_resource.should_receive(:process) + CanCan::ControllerResource.stub(:new).with(@controller, nil, :load => true, :authorize => true) { controller_resource } + @controller_class.should_receive(:before_filter).with(:only => 1, :except => 2, :if => 3, :unless => 4).and_yield(@controller) + @controller_class.load_and_authorize_resource :only => 1, :except => 2, :if => 3, :unless => 4 + end + + it "load_and_authorize_resource with :prepend prepends the before filter" do @controller_class.should_receive(:prepend_before_filter).with({}) @controller_class.load_and_authorize_resource :foo => :bar, :prepend => true end diff --git a/spec/cancan/controller_resource_spec.rb b/spec/cancan/controller_resource_spec.rb index e37e9ec..9ead114 100644 --- a/spec/cancan/controller_resource_spec.rb +++ b/spec/cancan/controller_resource_spec.rb @@ -35,6 +35,26 @@ describe CanCan::ControllerResource do @controller.instance_variable_get(:@project).should == project end + it "attempts to load a resource with the same namespace as the controller when using :: for namespace" do + module SomeEngine + class Project < ::Project; end + end + project = SomeEngine::Project.create! + @params.merge!(:controller => "SomeEngine::ProjectsController", :action => "show", :id => project.id) + CanCan::ControllerResource.new(@controller, :load => true).process + @controller.instance_variable_get(:@project).should == project + end + + # Rails includes namespace in params, see issue #349 + it "creates through the namespaced params" do + module SomeEngine + class Project < ::Project; end + end + @params.merge!(:controller => "SomeEngine::ProjectsController", :action => "create", :some_engine_project => {:name => "foobar"}) + CanCan::ControllerResource.new(@controller, :load => true).process + @controller.instance_variable_get(:@project).name.should == "foobar" + end + it "loads resource for namespaced controller when using '::' for namespace" do project = Project.create! @params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id) @@ -48,6 +68,15 @@ describe CanCan::ControllerResource do @controller.instance_variable_get(:@project).name.should == "foobar" end + it "builds a new resource for namespaced model with hash if params[:id] is not specified" do + module SomeEngine + class Project < ::Project; end + end + @params.merge!(:action => "create", :some_engine_project => {:name => "foobar"}) + CanCan::ControllerResource.new(@controller, :load => true, :class => SomeEngine::Project).process + @controller.instance_variable_get(:@project).name.should == "foobar" + end + it "builds a new resource with attributes from current ability" do @params.merge!(:action => "new") @ability.can(:create, :projects, :name => "from conditions") @@ -169,6 +198,11 @@ describe CanCan::ControllerResource do resource.should_not be_parent end + it "has the specified resource_class if name is passed to load_resource" do + resource = CanCan::ControllerResource.new(@controller, :category) + resource.send(:resource_class).should == Category + end + it "loads parent resource through proper id parameter" do project = Project.create! @params.merge!(:action => "index", :project_id => project.id) @@ -226,23 +260,18 @@ describe CanCan::ControllerResource do it "named resources should be loaded independently of the controller name" do category = Category.create! @params.merge!(:action => "new", :category_id => category.id) - CanCan::ControllerResource.new(@controller, :category, :load => true).process CanCan::ControllerResource.new(@controller, :project, :load => true, :through => :category).process - @controller.instance_variable_get(:@category).should eq(category) - project = @controller.instance_variable_get(:@project) project.category.should eq(category) end - + it "parent resources shouldn't be altered" do category = Category.create! @params.merge!(:action => "create", :category_id => category.id, :project => { :name => 'foo' }) - CanCan::ControllerResource.new(@controller, :category, :load => true).process CanCan::ControllerResource.new(@controller, :project, :load => true, :through => :category).process - project = @controller.instance_variable_get(:@project) project.new_record?.should eq(true) project.name.should eq('foo') @@ -329,6 +358,16 @@ describe CanCan::ControllerResource do @controller.instance_variable_get(:@project).should == project end + it "loads the model using a custom namespaced class" do + module SomeEngine + class Project < ::Project; end + end + project = SomeEngine::Project.create! + @params.merge!(:action => "show", :id => project.id) + CanCan::ControllerResource.new(@controller, :load => true, :class => SomeEngine::Project).process + @controller.instance_variable_get(:@project).should == project + end + it "does not authorize based on resource name if class is false because we don't do class level authorization anymore" do @params.merge!(:action => "show", :id => 123) @controller.stub(:authorize!).with(:show, :projects) { raise CanCan::Unauthorized } diff --git a/spec/cancan/inherited_resource_spec.rb b/spec/cancan/inherited_resource_spec.rb index ea69c9c..12739df 100644 --- a/spec/cancan/inherited_resource_spec.rb +++ b/spec/cancan/inherited_resource_spec.rb @@ -39,4 +39,20 @@ describe CanCan::InheritedResource do CanCan::InheritedResource.new(@controller, :load => true).process @controller.instance_variable_get(:@projects).should == :projects end + + it "should build a new resource with attributes from current ability" do + @params[:action] = "new" + @ability.can(:create, :projects, :name => "from conditions") + @controller.stub(:build_resource) { Struct.new(:name).new } + CanCan::InheritedResource.new(@controller, :load => true).process + @controller.instance_variable_get(:@project).name.should == "from conditions" + end + + it "should override initial attributes with params" do + @params.merge!(:action => "new", :project => {:name => "from params"}) + @ability.can(:create, :projects, :name => "from conditions") + @controller.stub(:build_resource) { Struct.new(:name).new } + CanCan::ControllerResource.new(@controller, :load => true).process + @controller.instance_variable_get(:@project).name.should == "from params" + 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 2b41cae..6013368 100644 --- a/spec/cancan/model_adapters/active_record_adapter_spec.rb +++ b/spec/cancan/model_adapters/active_record_adapter_spec.rb @@ -228,6 +228,17 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record" @ability.should_not be_able_to(:read, article2) end + it "should merge MetaWhere and non-MetaWhere conditions" do + pending + @ability.can :read, Article, :priority.lt => 2 + @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) + end + it "matches any MetaWhere condition" do pending adapter = CanCan::ModelAdapters::ActiveRecordAdapter diff --git a/spec/cancan/model_adapters/mongoid_adapter_spec.rb b/spec/cancan/model_adapters/mongoid_adapter_spec.rb index 1e3bb5e..451e609 100644 --- a/spec/cancan/model_adapters/mongoid_adapter_spec.rb +++ b/spec/cancan/model_adapters/mongoid_adapter_spec.rb @@ -71,6 +71,18 @@ if ENV["MODEL_ADAPTER"] == "mongoid" MongoidProject.accessible_by(@ability, :read).entries.should == [sir] end + it "returns the correct records when a mix of can and cannot rules in defined ability" do + pending "TODO figure out why this isn't working" + @ability.can :manage, :mongoid_projects, :title => 'Sir' + @ability.cannot :destroy, :mongoid_projects + + sir = MongoidProject.create(:title => 'Sir') + lord = MongoidProject.create(:title => 'Lord') + dude = MongoidProject.create(:title => 'Dude') + + MongoidProject.accessible_by(@ability, :destroy).entries.should == [sir] + end + it "is able to mix empty conditions and hashes" do pending "TODO figure out why this isn't working" @ability.can :read, :mongoid_projects diff --git a/spec/cancan/rule_spec.rb b/spec/cancan/rule_spec.rb index 5fb8513..5aacc2c 100644 --- a/spec/cancan/rule_spec.rb +++ b/spec/cancan/rule_spec.rb @@ -1,4 +1,5 @@ require "spec_helper" +require "ostruct" # for OpenStruct below # Most of Rule functionality is tested in Ability specs describe CanCan::Rule do @@ -45,4 +46,10 @@ describe CanCan::Rule do CanCan::Rule.new(false, :read, :integers, :foo => :bar).specificity.should eq(4) CanCan::Rule.new(false, :read, :integers, :foo).specificity.should eq(4) 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 + end end