Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Adapter for MongoMapper #649

Closed
wants to merge 3 commits into from

5 participants

@maxprokopiev

Based on Mongoid adapter. Can you guys review it, please? I'm using it in my projects and seems like it's pretty sufficient for my needs.

@mikepack
Collaborator

Merges cleanly and specs pass.

@maxprokopiev

What about merging it?

@mikepack
Collaborator

That's up to @ryanb.

@showaltb

+1 for merging

@andhapp
Collaborator

@juggler: Thanks. Unfortunately, the 1.x branch (current master) is only for bug fixes. Can you please close this pull request and create another pull request for the 2.0 branch? Thanks.

@codegourmet

***DANGER, huge issue!
Plucky::Query.remove() actually calls collection.remove()
This will remove all the records matching rule.conditions from the database - which is not intended, I guess ... ;)

oops, I'll check this

Me too. Expect a pull request today.
Also thanks for all the specs! :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 21, 2012
  1. @maxprokopiev

    Add MongoMapper support

    maxprokopiev authored
Commits on May 31, 2012
  1. @maxprokopiev
Commits on Jun 16, 2012
  1. @maxprokopiev
This page is out of date. Refresh to see the latest.
View
3  Gemfile
@@ -13,6 +13,9 @@ when "data_mapper"
when "mongoid"
gem "bson_ext", "~> 1.1"
gem "mongoid", "~> 2.0.0.beta.20"
+when "mongo_mapper"
+ gem "bson_ext"
+ gem "mongo_mapper"
else
raise "Unknown model adapter: #{ENV["MODEL_ADAPTER"]}"
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, :focus => true do
+ context "MongoMapper defined" do
+ before(:each) do
+ @ability = Object.new
+ @ability.extend(CanCan::Ability)
+ end
+
+ after(:each) do
+ MongoMapperProject.destroy_all
+ end
+
+ it "should be 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 "should find record" do
+ project = MongoMapperProject.create
+ CanCan::ModelAdapters::MongoMapperAdapter.find(MongoMapperProject, project.id).should == project
+ end
+
+ it "should compare properties on mongomapper documents with the conditions hash" do
+ model = MongoMapperProject.new
+ @ability.can :read, MongoMapperProject, :id => model.id
+ @ability.should be_able_to(:read, model)
+ end
+
+ it "should be 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, MongoMapperProject, :numbers => 'one'
+ @ability.should be_able_to(:foo, one_to_three)
+ @ability.should_not be_able_to(:foo, two_to_five)
+ end
+
+ it "should return [] 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 "should return the correct records based on the defined ability" do
+ @ability.can :read, MongoMapperProject, :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 "should be able to mix empty conditions and hashes" do
+ @ability.can :read, MongoMapperProject
+ @ability.can :read, MongoMapperProject, :title => 'Sir'
+ sir = MongoMapperProject.create(:title => 'Sir')
+ lord = MongoMapperProject.create(:title => 'Lord')
+
+ MongoMapperProject.accessible_by(@ability, :read).count.should == 2
+ end
+
+ it "should return everything when the defined ability is manage all" do
+ @ability.can :manage, :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 "should call where with matching ability conditions" do
+ obj = MongoMapperProject.create(:foo => {:bar => 1})
+ @ability.can :read, MongoMapperProject, :foo => {:bar => 1}
+ MongoMapperProject.accessible_by(@ability, :read).entries.first.should == obj
+ end
+
+ it "should exclude from the result if set to cannot" do
+ obj = MongoMapperProject.create(:bar => 1)
+ obj2 = MongoMapperProject.create(:bar => 2)
+ @ability.can :read, MongoMapperProject
+ @ability.cannot :read, MongoMapperProject, :bar => 2
+ MongoMapperProject.accessible_by(@ability, :read).entries.should == [obj]
+ end
+
+ it "should combine the rules" do
+ obj = MongoMapperProject.create(:bar => 1)
+ obj2 = MongoMapperProject.create(:bar => 2)
+ obj3 = MongoMapperProject.create(:bar => 3)
+ @ability.can :read, MongoMapperProject, :bar => 1
+ @ability.can :read, MongoMapperProject, :bar => 2
+ MongoMapperProject.accessible_by(@ability, :read).entries.should =~ [obj, obj2]
+ end
+
+ end
+ end
+end
Something went wrong with that request. Please try again.