Fix bug with MongoidAdditions throwing a NameError when Mongoid is not defined by always checking if Mongoid is defined before referencing Mongoid-related constants
Also add spec for this bug
This commit is contained in:
parent
ebb8e1bf8b
commit
e14e1edec2
|
@ -1,10 +1,9 @@
|
||||||
module CanCan
|
module CanCan
|
||||||
|
|
||||||
module Ability
|
module Ability
|
||||||
# could use alias_method_chain, but it's not worth adding activesupport as a gem dependency
|
# could use alias_method_chain, but it's not worth adding activesupport as a gem dependency
|
||||||
alias_method :query_without_mongoid_support, :query
|
alias_method :query_without_mongoid_support, :query
|
||||||
def query(action, subject)
|
def query(action, subject)
|
||||||
if Object.const_defined?(:Mongoid) && subject <= CanCan::MongoidAdditions
|
if defined?(::Mongoid) && subject <= CanCan::MongoidAdditions
|
||||||
query_with_mongoid_support(action, subject)
|
query_with_mongoid_support(action, subject)
|
||||||
else
|
else
|
||||||
query_without_mongoid_support(action, subject)
|
query_without_mongoid_support(action, subject)
|
||||||
|
@ -47,7 +46,7 @@ module CanCan
|
||||||
# => true
|
# => true
|
||||||
class Rule
|
class Rule
|
||||||
def matches_conditions_hash_with_mongoid_subject?(subject, conditions = @conditions)
|
def matches_conditions_hash_with_mongoid_subject?(subject, conditions = @conditions)
|
||||||
if subject.class.include?(Mongoid::Document) && conditions.any?{|k,v| !k.kind_of?(Symbol)}
|
if defined?(::Mongoid) && subject.class.include?(::Mongoid::Document) && conditions.any?{|k,v| !k.kind_of?(Symbol)}
|
||||||
if conditions.empty?
|
if conditions.empty?
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
|
@ -98,7 +97,7 @@ end
|
||||||
|
|
||||||
# Info on monkeypatching Mongoid :
|
# Info on monkeypatching Mongoid :
|
||||||
# http://log.mazniak.org/post/719062325/monkey-patching-activesupport-concern-and-you#footer
|
# http://log.mazniak.org/post/719062325/monkey-patching-activesupport-concern-and-you#footer
|
||||||
if defined? Mongoid
|
if defined?(::Mongoid)
|
||||||
module Mongoid
|
module Mongoid
|
||||||
module Components
|
module Components
|
||||||
old_block = @_included_block
|
old_block = @_included_block
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
require 'mongoid' # require mongoid first so MongoidAdditions are loaded
|
||||||
require "spec_helper"
|
require "spec_helper"
|
||||||
require 'mongoid'
|
|
||||||
|
|
||||||
class MongoidCategory
|
class MongoidCategory
|
||||||
include Mongoid::Document
|
include Mongoid::Document
|
||||||
|
@ -38,129 +38,153 @@ Mongoid.configure do |config|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe CanCan::MongoidAdditions do
|
describe CanCan::MongoidAdditions do
|
||||||
before(:each) do
|
context "Mongoid not defined" do
|
||||||
@model_class = MongoidProject
|
before(:all) do
|
||||||
@ability = Object.new
|
@mongoid_class = Object.send(:remove_const, :Mongoid)
|
||||||
@ability.extend(CanCan::Ability)
|
|
||||||
end
|
|
||||||
|
|
||||||
after(:each) do
|
|
||||||
Mongoid.master.collections.select do |collection|
|
|
||||||
collection.name !~ /system/
|
|
||||||
end.each(&:drop)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should compare properties on mongoid documents with the conditions hash" do
|
|
||||||
model = @model_class.new
|
|
||||||
@ability.can :read, @model_class, :id => model.id
|
|
||||||
@ability.should be_able_to :read, model
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return [] when no ability is defined so no records are found" do
|
|
||||||
@model_class.create :title => 'Sir'
|
|
||||||
@model_class.create :title => 'Lord'
|
|
||||||
@model_class.create :title => 'Dude'
|
|
||||||
|
|
||||||
@model_class.accessible_by(@ability, :read).entries.should == []
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return the correct records based on the defined ability" do
|
|
||||||
@ability.can :read, @model_class, :title => "Sir"
|
|
||||||
sir = @model_class.create :title => 'Sir'
|
|
||||||
lord = @model_class.create :title => 'Lord'
|
|
||||||
dude = @model_class.create :title => 'Dude'
|
|
||||||
|
|
||||||
@model_class.accessible_by(@ability, :read).should == [sir]
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return everything when the defined ability is manage all" do
|
|
||||||
@ability.can :manage, :all
|
|
||||||
sir = @model_class.create :title => 'Sir'
|
|
||||||
lord = @model_class.create :title => 'Lord'
|
|
||||||
dude = @model_class.create :title => 'Dude'
|
|
||||||
|
|
||||||
@model_class.accessible_by(@ability, :read).entries.should == [sir, lord, dude]
|
|
||||||
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
|
|
||||||
@model_class.accessible_by(@ability, :read).should == [obj]
|
|
||||||
|
|
||||||
obj2 = @model_class.create :title => 'Lord'
|
|
||||||
@ability.can?(:read, obj2).should == false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "activates only when there are Criteria in the hash" do
|
after(:all) do
|
||||||
it "Calls where on the model class when there are criteria" do
|
Object.const_set(:Mongoid, @mongoid_class)
|
||||||
obj = @model_class.create :title => 'Bird'
|
|
||||||
@conditions = {:title.nin => ["Fork", "Spoon"]}
|
|
||||||
mock(@model_class).where(@conditions) {[obj]}
|
|
||||||
@ability.can :read, @model_class, @conditions
|
|
||||||
@ability.should be_able_to(:read, obj)
|
|
||||||
end
|
|
||||||
it "Calls the base version if there are no mongoid criteria" do
|
|
||||||
obj = @model_class.new :title => 'Bird'
|
|
||||||
@conditions = {:id => obj.id}
|
|
||||||
@ability.can :read, @model_class, @conditions
|
|
||||||
@ability.should be_able_to(:read, obj)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
it "should not raise an error for ActiveRecord models" do
|
||||||
it "should handle :field.nin" do
|
@model_class = Class.new(Project)
|
||||||
obj = @model_class.create :title => 'Sir'
|
stub(@model_class).scoped { :scoped_stub }
|
||||||
@ability.can :read, @model_class, :title.nin => ["Lord", "Madam"]
|
@model_class.send(:include, CanCan::ActiveRecordAdditions)
|
||||||
@ability.can?(:read, obj).should == true
|
@ability = Object.new
|
||||||
@model_class.accessible_by(@ability, :read).should == [obj]
|
@ability.extend(CanCan::Ability)
|
||||||
|
|
||||||
obj2 = @model_class.create :title => 'Lord'
|
@ability.can :read, @model_class
|
||||||
@ability.can?(:read, obj2).should == false
|
lambda {
|
||||||
end
|
@ability.can? :read, @model_class.new
|
||||||
|
}.should_not raise_error
|
||||||
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
|
|
||||||
@model_class.accessible_by(@ability, :read).should == [obj]
|
|
||||||
|
|
||||||
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
|
|
||||||
@model_class.accessible_by(@ability, :read).should == [obj]
|
|
||||||
|
|
||||||
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
|
|
||||||
@model_class.accessible_by(@ability, :read).should == [obj]
|
|
||||||
|
|
||||||
obj2 = @model_class.create :age => 40
|
|
||||||
@ability.can?(:read, obj2).should == false
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "Mongoid defined" do
|
||||||
|
before(:each) do
|
||||||
|
@model_class = MongoidProject
|
||||||
|
@ability = Object.new
|
||||||
|
@ability.extend(CanCan::Ability)
|
||||||
|
end
|
||||||
|
|
||||||
it "should call where with matching ability conditions" do
|
after(:each) do
|
||||||
obj = @model_class.create :foo => {:bar => 1}
|
Mongoid.master.collections.select do |collection|
|
||||||
@ability.can :read, @model_class, :foo => {:bar => 1}
|
collection.name !~ /system/
|
||||||
@model_class.accessible_by(@ability, :read).entries.first.should == obj
|
end.each(&:drop)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should not allow to fetch records when ability with just block present" do
|
it "should compare properties on mongoid documents with the conditions hash" do
|
||||||
@ability.can :read, @model_class do false end
|
model = @model_class.new
|
||||||
lambda {
|
@ability.can :read, @model_class, :id => model.id
|
||||||
@model_class.accessible_by(@ability)
|
@ability.should be_able_to :read, model
|
||||||
}.should raise_error(CanCan::Error)
|
end
|
||||||
|
|
||||||
|
it "should return [] when no ability is defined so no records are found" do
|
||||||
|
@model_class.create :title => 'Sir'
|
||||||
|
@model_class.create :title => 'Lord'
|
||||||
|
@model_class.create :title => 'Dude'
|
||||||
|
|
||||||
|
@model_class.accessible_by(@ability, :read).entries.should == []
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return the correct records based on the defined ability" do
|
||||||
|
@ability.can :read, @model_class, :title => "Sir"
|
||||||
|
sir = @model_class.create :title => 'Sir'
|
||||||
|
lord = @model_class.create :title => 'Lord'
|
||||||
|
dude = @model_class.create :title => 'Dude'
|
||||||
|
|
||||||
|
@model_class.accessible_by(@ability, :read).should == [sir]
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return everything when the defined ability is manage all" do
|
||||||
|
@ability.can :manage, :all
|
||||||
|
sir = @model_class.create :title => 'Sir'
|
||||||
|
lord = @model_class.create :title => 'Lord'
|
||||||
|
dude = @model_class.create :title => 'Dude'
|
||||||
|
|
||||||
|
@model_class.accessible_by(@ability, :read).entries.should == [sir, lord, dude]
|
||||||
|
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
|
||||||
|
@model_class.accessible_by(@ability, :read).should == [obj]
|
||||||
|
|
||||||
|
obj2 = @model_class.create :title => 'Lord'
|
||||||
|
@ability.can?(:read, obj2).should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "activates only when there are Criteria in the hash" do
|
||||||
|
it "Calls where on the model class when there are criteria" do
|
||||||
|
obj = @model_class.create :title => 'Bird'
|
||||||
|
@conditions = {:title.nin => ["Fork", "Spoon"]}
|
||||||
|
mock(@model_class).where(@conditions) {[obj]}
|
||||||
|
@ability.can :read, @model_class, @conditions
|
||||||
|
@ability.should be_able_to(:read, obj)
|
||||||
|
end
|
||||||
|
it "Calls the base version if there are no mongoid criteria" do
|
||||||
|
obj = @model_class.new :title => 'Bird'
|
||||||
|
@conditions = {:id => obj.id}
|
||||||
|
@ability.can :read, @model_class, @conditions
|
||||||
|
@ability.should be_able_to(:read, obj)
|
||||||
|
end
|
||||||
|
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
|
||||||
|
@model_class.accessible_by(@ability, :read).should == [obj]
|
||||||
|
|
||||||
|
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
|
||||||
|
@model_class.accessible_by(@ability, :read).should == [obj]
|
||||||
|
|
||||||
|
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
|
||||||
|
@model_class.accessible_by(@ability, :read).should == [obj]
|
||||||
|
|
||||||
|
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
|
||||||
|
@model_class.accessible_by(@ability, :read).should == [obj]
|
||||||
|
|
||||||
|
obj2 = @model_class.create :age => 40
|
||||||
|
@ability.can?(:read, obj2).should == false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should call where with matching ability conditions" do
|
||||||
|
obj = @model_class.create :foo => {:bar => 1}
|
||||||
|
@ability.can :read, @model_class, :foo => {:bar => 1}
|
||||||
|
@model_class.accessible_by(@ability, :read).entries.first.should == obj
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should not allow to fetch records when ability with just block present" do
|
||||||
|
@ability.can :read, @model_class do false end
|
||||||
|
lambda {
|
||||||
|
@model_class.accessible_by(@ability)
|
||||||
|
}.should raise_error(CanCan::Error)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue
Block a user