Add support for Mongoid::Criteria Symbol extensions (:age.gt => 10) along with specs.

This commit is contained in:
Mani Tadayon 2010-10-13 15:22:53 -07:00
parent be74df0548
commit ab82dcbc8f
3 changed files with 89 additions and 3 deletions

View File

@ -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

View File

@ -26,6 +26,42 @@ module CanCan
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

View File

@ -3,11 +3,14 @@ require 'mongoid'
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 @@ end
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 @@ describe CanCan::MongoidAdditions do
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}