Add support and tests for datamapper.
This broke some of the mongoid tests and I don't know how to fix them. Both packages define Symbol#in, and when you load them both things don't behave properly. Hopefully someone more versed in mongoid can rewrite the spec to not depend on the Symbol extensions.
This commit is contained in:
parent
2d31cbdf60
commit
d315e22e7a
|
@ -17,7 +17,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 'dm-core', '~> 1.0.2'
|
||||
|
||||
s.rubyforge_project = s.name
|
||||
s.required_rubygems_version = ">= 1.3.4"
|
||||
end
|
||||
|
|
69
lib/cancan/data_mapper_additions.rb
Normal file
69
lib/cancan/data_mapper_additions.rb
Normal file
|
@ -0,0 +1,69 @@
|
|||
require 'dm-core'
|
||||
|
||||
module CanCan
|
||||
module Ability
|
||||
# could use alias_method_chain, but it's not worth adding activesupport as a gem dependency
|
||||
alias_method :query_without_data_mapper_support, :query
|
||||
def query(action, subject)
|
||||
if Object.const_defined?('DataMapper') && subject <= DataMapper::Resource
|
||||
query_with_data_mapper_support(action, subject)
|
||||
else
|
||||
query_without_data_mapper_support(action, subject)
|
||||
end
|
||||
end
|
||||
|
||||
def query_with_data_mapper_support(action, subject)
|
||||
DataMapperQuery.new(subject, relevant_rules_for_query(action, subject))
|
||||
end
|
||||
end
|
||||
|
||||
class DataMapperQuery
|
||||
def initialize(sanitizer, rules)
|
||||
@sanitizer = sanitizer
|
||||
@rules = rules
|
||||
end
|
||||
|
||||
def conditions
|
||||
@rules.map {|r| r.instance_variable_get(:@conditions) }
|
||||
end
|
||||
end
|
||||
|
||||
# This module is automatically included into all Active Record models.
|
||||
module DataMapperAdditions
|
||||
module ClassMethods
|
||||
# Returns a scope which fetches only the records that the passed ability
|
||||
# can perform a given action on. The action defaults to :read. This
|
||||
# is usually called from a controller and passed the +current_ability+.
|
||||
#
|
||||
# @articles = Article.accessible_by(current_ability)
|
||||
#
|
||||
# Here only the articles which the user is able to read will be returned.
|
||||
# If the user does not have permission to read any articles then an empty
|
||||
# result is returned. Since this is a scope it can be combined with any
|
||||
# other scopes or pagination.
|
||||
#
|
||||
# An alternative action can optionally be passed as a second argument.
|
||||
#
|
||||
# @articles = Article.accessible_by(current_ability, :update)
|
||||
#
|
||||
# Here only the articles which the user can update are returned. This
|
||||
# internally uses Ability#conditions method, see that for more information.
|
||||
def accessible_by(ability, action = :read)
|
||||
query = ability.query(action, self)
|
||||
|
||||
scope = all(:conditions => ['true=false'])
|
||||
query.conditions.each do |condition|
|
||||
scope += all(:conditions => condition)
|
||||
end
|
||||
|
||||
return scope
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if Object.const_defined?('DataMapper')
|
||||
DataMapper::Model.class_eval do
|
||||
include CanCan::DataMapperAdditions::ClassMethods
|
||||
end
|
||||
end
|
59
spec/cancan/data_mapper_additions_spec.rb
Normal file
59
spec/cancan/data_mapper_additions_spec.rb
Normal file
|
@ -0,0 +1,59 @@
|
|||
require "spec_helper"
|
||||
require 'cancan/data_mapper_additions'
|
||||
|
||||
describe CanCan::DataMapperAdditions do
|
||||
before(:each) do
|
||||
@model_class = Class.new
|
||||
@model_class.class_eval do
|
||||
include DataMapper::Resource
|
||||
end
|
||||
stub(@model_class).all(:conditions => ['true=false']) { 'no-match:' }
|
||||
|
||||
@ability = Object.new
|
||||
@ability.extend(CanCan::Ability)
|
||||
end
|
||||
|
||||
it "should return no records when no ability is defined so no records are found" do
|
||||
@model_class.accessible_by(@ability, :read).should == 'no-match:'
|
||||
end
|
||||
|
||||
it "should call all with matching ability conditions" do
|
||||
@ability.can :read, @model_class, :foo => {:bar => 1}
|
||||
stub(@model_class).all(:conditions => {:foo => {:bar => 1}}) { 'found-records:' }
|
||||
@model_class.accessible_by(@ability, :read).should == 'no-match:found-records:'
|
||||
end
|
||||
|
||||
it "should merge association joins and sanitize conditions" do
|
||||
@ability.can :read, @model_class, :foo => {:bar => 1}
|
||||
@ability.can :read, @model_class, :too => {:car => 1, :far => {:bar => 1}}
|
||||
|
||||
stub(@model_class).all(:conditions => {:foo => {:bar => 1}}) { 'foo:' }
|
||||
stub(@model_class).all(:conditions => {:too => {:car => 1, :far => {:bar => 1}}}) { 'too:' }
|
||||
|
||||
@model_class.accessible_by(@ability).should == 'no-match:too:foo:'
|
||||
end
|
||||
|
||||
it "should allow to define sql conditions by not hash" do
|
||||
@ability.can :read, @model_class, :foo => 1
|
||||
@ability.can :read, @model_class, ['bar = ?', 1]
|
||||
|
||||
stub(@model_class).all(:conditions => {:foo => 1}) { 'foo:' }
|
||||
stub(@model_class).all(:conditions => ['bar = ?', 1]) { 'bar:' }
|
||||
|
||||
@model_class.accessible_by(@ability).should == 'no-match:bar:foo:'
|
||||
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
|
||||
|
||||
it "should not allow to check ability on object when nonhash sql ability definition without block present" do
|
||||
@ability.can :read, @model_class, ['bar = ?', 1]
|
||||
lambda {
|
||||
@ability.can? :read, @model_class.new
|
||||
}.should raise_error(CanCan::Error)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue
Block a user