Permalink
Browse files

Add support for Mongoid::Criteria Symbol extensions (:age.gt => 10) a…

…long with specs.
  • Loading branch information...
1 parent be74df0 commit ab82dcbc8fba5daf59c7c435e32b7067e5995e26 @bowsersenior bowsersenior committed Oct 13, 2010
Showing with 89 additions and 3 deletions.
  1. +2 −0 cancan.gemspec
  2. +36 −0 lib/cancan/mongoid_additions.rb
  3. +51 −3 spec/cancan/mongoid_additions_spec.rb
View
@@ -18,6 +18,8 @@ Gem::Specification.new do |s|
s.add_development_dependency 'mongoid', '~> 2.0.0.beta.19'
s.add_development_dependency 'bson_ext', '~> 1.1'
+ s.add_development_dependency 'ruby-debug'
+
s.rubyforge_project = s.name
s.required_rubygems_version = ">= 1.3.4"
end
@@ -26,6 +26,42 @@ def conditions
end
end
+ # customize to handle Mongoid queries in ability definitions conditions
+ class CanDefinition
+ def matches_conditions_hash?(subject, conditions = @conditions)
+ if subject.class.include?(Mongoid::Document) # Mongoid Criteria are simpler to check than normal conditions hashes
+ if conditions.empty? # When no conditions are given, true should be returned.
+ # The default CanCan behavior relies on the fact that conditions.all? will return true when conditions is empty
+ # The way ruby handles all? for empty hashes can be unexpected:
+ # {}.all?{|a| a == 5}
+ # => true
+ # {}.all?{|a| a != 5}
+ # => true
+ true
+ else
+ subject.class.where(conditions).include?(subject) # just use Mongoid's where function
+ end
+ else
+ conditions.all? do |name, value|
+ attribute = subject.send(name)
+ if value.kind_of?(Hash)
+ if attribute.kind_of? Array
+ attribute.any? { |element| matches_conditions_hash? element, value }
+ else
+ matches_conditions_hash? attribute, value
+ end
+ elsif value.kind_of?(Array) || value.kind_of?(Range)
+ value.include? attribute
+ else
+ attribute == value
+ end
+ end
+ end
+ end
+ end
+
+
+
module MongoidAdditions
module ClassMethods
# Returns a scope which fetches only the records that the passed ability
@@ -3,11 +3,14 @@
class MongoidCategory
include Mongoid::Document
+ include CanCan::MongoidAdditions
+
references_many :mongoid_projects
end
class MongoidProject
include Mongoid::Document
+ include CanCan::MongoidAdditions
referenced_in :mongoid_category
@@ -36,9 +39,7 @@ def sanitize_hash(hash)
describe CanCan::MongoidAdditions do
before(:each) do
- @model_class = Class.new(MongoidProject)
- stub(@model_class).scoped { :scoped_stub }
- @model_class.send(:include, CanCan::MongoidAdditions)
+ @model_class = MongoidProject
@ability = Object.new
@ability.extend(CanCan::Ability)
end
@@ -52,6 +53,53 @@ def sanitize_hash(hash)
it "should return [] when no ability is defined so no records are found" do
@model_class.accessible_by(@ability, :read).should == []
end
+
+ describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do
+ it "should handle :field.in" do
+ obj = @model_class.create :title => 'Sir'
+ @ability.can :read, @model_class, :title.in => ["Sir", "Madam"]
+ @ability.can?(:read, obj).should == true
+
+ obj2 = @model_class.create :title => 'Lord'
+ @ability.can?(:read, obj2).should == false
+ end
+
+ it "should handle :field.nin" do
+ obj = @model_class.create :title => 'Sir'
+ @ability.can :read, @model_class, :title.nin => ["Lord", "Madam"]
+ @ability.can?(:read, obj).should == true
+
+ obj2 = @model_class.create :title => 'Lord'
+ @ability.can?(:read, obj2).should == false
+ end
+
+ it "should handle :field.size" do
+ obj = @model_class.create :titles => ['Palatin', 'Margrave']
+ @ability.can :read, @model_class, :titles.size => 2
+ @ability.can?(:read, obj).should == true
+
+ obj2 = @model_class.create :titles => ['Palatin', 'Margrave', 'Marquis']
+ @ability.can?(:read, obj2).should == false
+ end
+
+ it "should handle :field.exists" do
+ obj = @model_class.create :titles => ['Palatin', 'Margrave']
+ @ability.can :read, @model_class, :titles.exists => true
+ @ability.can?(:read, obj).should == true
+
+ obj2 = @model_class.create
+ @ability.can?(:read, obj2).should == false
+ end
+
+ it "should handle :field.gt" do
+ obj = @model_class.create :age => 50
+ @ability.can :read, @model_class, :age.gt => 45
+ @ability.can?(:read, obj).should == true
+
+ obj2 = @model_class.create :age => 40
+ @ability.can?(:read, obj2).should == false
+ end
+ end
it "should call where with matching ability conditions" do
@ability.can :read, @model_class, :foo => {:bar => 1}

0 comments on commit ab82dcb

Please sign in to comment.