Skip to content
Browse files

Add MongoMapper support

  • Loading branch information...
1 parent 6886aec commit a06703b20860d77bd00558e881213b1445d1804d @maxprokopiev committed
View
2 Rakefile
@@ -9,7 +9,7 @@ end
desc "Run specs for all adapters"
task :spec_all do
- %w[active_record data_mapper mongoid].each do |model_adapter|
+ %w[active_record data_mapper mongoid mongo_mapper].each do |model_adapter|
puts "MODEL_ADAPTER = #{model_adapter}"
system "rake spec MODEL_ADAPTER=#{model_adapter}"
end
View
2 cancan.gemspec
@@ -21,6 +21,8 @@ Gem::Specification.new do |s|
s.add_development_dependency "mongoid", "~> 2.4.8"
s.add_development_dependency "bson_ext", "~> 1.6.2"
+ s.add_development_dependency "mongo_mapper", "~> 0.11.1"
+
s.rubyforge_project = s.name
s.required_rubygems_version = ">= 1.3.4"
end
View
1 lib/cancan.rb
@@ -11,3 +11,4 @@
require 'cancan/model_adapters/active_record_adapter' if defined? ActiveRecord
require 'cancan/model_adapters/data_mapper_adapter' if defined? DataMapper
require 'cancan/model_adapters/mongoid_adapter' if defined?(Mongoid) && defined?(Mongoid::Document)
+require 'cancan/model_adapters/mongo_mapper_adapter' if defined?(MongoMapper) && defined?(MongoMapper::Document)
View
51 lib/cancan/model_adapters/mongo_mapper_adapter.rb
@@ -0,0 +1,51 @@
+module CanCan
+ module ModelAdapters
+ class MongoMapperAdapter < AbstractAdapter
+ def self.for_class?(model_class)
+ model_class <= MongoMapper::Document
+ end
+
+ def self.override_conditions_hash_matching?(subject, conditions)
+ conditions.any? do |k,v|
+ key_is_not_symbol = lambda { !k.kind_of?(Symbol) }
+ subject_value_is_array = lambda do
+ subject.respond_to?(k) && subject.send(k).is_a?(Array)
+ end
+
+ key_is_not_symbol.call || subject_value_is_array.call
+ end
+ end
+
+ def self.matches_conditions_hash?(subject, conditions)
+ subject.class.where(conditions).include? subject
+ end
+
+ def database_records
+ if @rules.size == 0
+ @model_class.where(:_id => {:$exists => false, :$type => 7}) # return no records
+ elsif @rules.size == 1
+ @model_class.where(@rules[0].conditions)
+ else
+ # we only need to process can rules if
+ # there are no rules with empty conditions
+ rules = @rules.reject { |rule| rule.conditions.empty? }
+ process_can_rules = @rules.count == rules.count
+ rules.inject(@model_class.where) do |records, rule|
+ if process_can_rules && rule.base_behavior
+ records.where rule.conditions
+ elsif !rule.base_behavior
+ records.remove rule.conditions
+ records
+ else
+ records
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+module MongoMapper::Document::ClassMethods
+ include CanCan::ModelAdditions::ClassMethods
+end
View
108 spec/cancan/model_adapters/mongo_mapper_adapter_spec.rb
@@ -0,0 +1,108 @@
+if ENV["MODEL_ADAPTER"] == "mongo_mapper"
+ require "spec_helper"
+
+ MongoMapper.connection = Mongo::Connection.new('localhost', 27017)
+ MongoMapper.database = "cancan_mongomapper_spec"
+
+ class MongoMapperProject
+ include MongoMapper::Document
+ end
+
+ describe CanCan::ModelAdapters::MongoMapperAdapter do
+ context "MongoMapper defined" do
+ before(:each) do
+ @ability = Object.new
+ @ability.extend(CanCan::Ability)
+ end
+
+ after(:each) do
+ MongoMapperProject.destroy_all
+ end
+
+ it "is for only MongoMapper classes" do
+ CanCan::ModelAdapters::MongoMapperAdapter.should_not be_for_class(Object)
+ CanCan::ModelAdapters::MongoMapperAdapter.should be_for_class(MongoMapperProject)
+ CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoMapperProject).should == CanCan::ModelAdapters::MongoMapperAdapter
+ end
+
+ it "finds record" do
+ project = MongoMapperProject.create
+ CanCan::ModelAdapters::MongoMapperAdapter.find(MongoMapperProject, project.id).should == project
+ end
+
+ it "compares properties on mongomapper documents with the conditions hash" do
+ model = MongoMapperProject.new
+ @ability.can :read, :mongo_mapper_projects, :id => model.id
+ @ability.should be_able_to(:read, model)
+ end
+
+ it "is able to read hashes when field is array" do
+ one_to_three = MongoMapperProject.create(:numbers => ['one', 'two', 'three'])
+ two_to_five = MongoMapperProject.create(:numbers => ['two', 'three', 'four', 'five'])
+
+ @ability.can :foo, :mongo_mapper_projects, :numbers => 'one'
+ @ability.should be_able_to(:foo, one_to_three)
+ @ability.should_not be_able_to(:foo, two_to_five)
+ end
+
+ it "returns [] when no ability is defined so no records are found" do
+ MongoMapperProject.create
+ MongoMapperProject.create
+ MongoMapperProject.create
+
+ MongoMapperProject.accessible_by(@ability, :read).entries.should == []
+ end
+
+ it "returns the correct records based on the defined ability" do
+ @ability.can :read, :mongo_mapper_projects, :title => "Sir"
+ sir = MongoMapperProject.create(:title => 'Sir')
+ lord = MongoMapperProject.create(:title => 'Lord')
+ dude = MongoMapperProject.create(:title => 'Dude')
+
+ MongoMapperProject.accessible_by(@ability, :read).entries.should == [sir]
+ end
+
+ it "is able to mix empty conditions and hashes" do
+ @ability.can :read, :mongo_mapper_projects, :title => 'Sir'
+ @ability.can :read, :mongo_mapper_projects
+ sir = MongoMapperProject.create(:title => 'Sir')
+ lord = MongoMapperProject.create(:title => 'Lord')
+
+ MongoMapperProject.accessible_by(@ability, :read).count.should == 2
+ end
+
+ it "returns everything when the defined ability is access all" do
+ @ability.can :access, :all
+ sir = MongoMapperProject.create(:title => 'Sir')
+ lord = MongoMapperProject.create(:title => 'Lord')
+ dude = MongoMapperProject.create(:title => 'Dude')
+
+ MongoMapperProject.accessible_by(@ability, :read).entries.should == [sir, lord, dude]
+ end
+
+ it "calls where with matching ability conditions" do
+ obj = MongoMapperProject.create(:foo => {:bar => 1})
+ @ability.can :read, :mongo_mapper_projects, :foo => {:bar => 1}
+ MongoMapperProject.accessible_by(@ability, :read).entries.first.should == obj
+ end
+
+ it "excludes from the result if set to cannot" do
+ obj = MongoMapperProject.create(:bar => 1)
+ obj2 = MongoMapperProject.create(:bar => 2)
+ @ability.can :read, :mongo_mapper_projects
+ @ability.cannot :read, :mongo_mapper_projects, :bar => 2
+ MongoMapperProject.accessible_by(@ability, :read).entries.should == [obj]
+ end
+
+ it "combines the rules" do
+ obj = MongoMapperProject.create(:bar => 1)
+ obj2 = MongoMapperProject.create(:bar => 2)
+ obj3 = MongoMapperProject.create(:bar => 3)
+ @ability.can :read, :mongo_mapper_projects, :bar => 1
+ @ability.can :read, :mongo_mapper_projects, :bar => 2
+ MongoMapperProject.accessible_by(@ability, :read).entries.should =~ [obj, obj2]
+ end
+
+ end
+ end
+end
View
2 spec/spec_helper.rb
@@ -11,6 +11,8 @@
require "dm-migrations"
when "mongoid"
require "mongoid"
+when "mongo_mapper"
+ require "mongo_mapper"
end
require 'active_support/all'

0 comments on commit a06703b

Please sign in to comment.
Something went wrong with that request. Please try again.