Add support for Mongoid documents along with basic specs.
This commit is contained in:
parent
f901c367fc
commit
be74df0548
|
@ -15,6 +15,9 @@ Gem::Specification.new do |s|
|
||||||
s.add_development_dependency 'rr', '~> 0.10.11' # 1.0.0 has respond_to? issues: http://github.com/btakita/rr/issues/issue/43
|
s.add_development_dependency 'rr', '~> 0.10.11' # 1.0.0 has respond_to? issues: http://github.com/btakita/rr/issues/issue/43
|
||||||
s.add_development_dependency 'supermodel', '~> 0.1.4'
|
s.add_development_dependency 'supermodel', '~> 0.1.4'
|
||||||
|
|
||||||
|
s.add_development_dependency 'mongoid', '~> 2.0.0.beta.19'
|
||||||
|
s.add_development_dependency 'bson_ext', '~> 1.1'
|
||||||
|
|
||||||
s.rubyforge_project = s.name
|
s.rubyforge_project = s.name
|
||||||
s.required_rubygems_version = ">= 1.3.4"
|
s.required_rubygems_version = ">= 1.3.4"
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,6 +3,7 @@ require 'cancan/can_definition'
|
||||||
require 'cancan/controller_resource'
|
require 'cancan/controller_resource'
|
||||||
require 'cancan/controller_additions'
|
require 'cancan/controller_additions'
|
||||||
require 'cancan/active_record_additions'
|
require 'cancan/active_record_additions'
|
||||||
|
require 'cancan/mongoid_additions'
|
||||||
require 'cancan/exceptions'
|
require 'cancan/exceptions'
|
||||||
require 'cancan/query'
|
require 'cancan/query'
|
||||||
require 'cancan/inherited_resource'
|
require 'cancan/inherited_resource'
|
||||||
|
|
78
lib/cancan/mongoid_additions.rb
Normal file
78
lib/cancan/mongoid_additions.rb
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
module CanCan
|
||||||
|
|
||||||
|
module Ability
|
||||||
|
alias_method :query_without_mongoid_support, :query
|
||||||
|
def query(action, subject)
|
||||||
|
if Object.const_defined?(:Mongoid) && subject <= CanCan::MongoidAdditions
|
||||||
|
query_with_mongoid_support(action, subject)
|
||||||
|
else
|
||||||
|
query_without_mongoid_support(action, subject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def query_with_mongoid_support(action, subject)
|
||||||
|
MongoidQuery.new(subject, relevant_can_definitions_for_query(action, subject))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class MongoidQuery
|
||||||
|
def initialize(sanitizer, can_definitions)
|
||||||
|
@sanitizer = sanitizer
|
||||||
|
@can_definitions = can_definitions
|
||||||
|
end
|
||||||
|
|
||||||
|
def conditions
|
||||||
|
@can_definitions.first.try(:tableized_conditions)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module MongoidAdditions
|
||||||
|
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)
|
||||||
|
if query.conditions.blank?
|
||||||
|
# this query is sure to return no results
|
||||||
|
# we need this so there is a Mongoid::Criteria object to return, since an empty array would cause problems
|
||||||
|
where({:_id => {'$exists' => true, '$type' => 2}})
|
||||||
|
else
|
||||||
|
where(query.conditions)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.included(base)
|
||||||
|
base.extend ClassMethods
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Info on monkeypatching Mongoid :
|
||||||
|
# http://log.mazniak.org/post/719062325/monkey-patching-activesupport-concern-and-you#footer
|
||||||
|
if defined? Mongoid
|
||||||
|
module Mongoid
|
||||||
|
module Components
|
||||||
|
old_block = @_included_block
|
||||||
|
@_included_block = Proc.new do
|
||||||
|
class_eval(&old_block) if old_block
|
||||||
|
include CanCan::MongoidAdditions
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
67
spec/cancan/mongoid_additions_spec.rb
Normal file
67
spec/cancan/mongoid_additions_spec.rb
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
require "spec_helper"
|
||||||
|
require 'mongoid'
|
||||||
|
|
||||||
|
class MongoidCategory
|
||||||
|
include Mongoid::Document
|
||||||
|
references_many :mongoid_projects
|
||||||
|
end
|
||||||
|
|
||||||
|
class MongoidProject
|
||||||
|
include Mongoid::Document
|
||||||
|
|
||||||
|
referenced_in :mongoid_category
|
||||||
|
|
||||||
|
class << self
|
||||||
|
protected
|
||||||
|
|
||||||
|
def sanitize_sql(hash_cond)
|
||||||
|
hash_cond
|
||||||
|
end
|
||||||
|
|
||||||
|
def sanitize_hash(hash)
|
||||||
|
hash.map do |name, value|
|
||||||
|
if Hash === value
|
||||||
|
sanitize_hash(value).map{|cond| "#{name}.#{cond}"}
|
||||||
|
else
|
||||||
|
"#{name}=#{value}"
|
||||||
|
end
|
||||||
|
end.flatten
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Mongoid.configure do |config|
|
||||||
|
config.master = Mongo::Connection.new('127.0.0.1', 27017).db("workflow_on_mongoid")
|
||||||
|
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)
|
||||||
|
@ability = Object.new
|
||||||
|
@ability.extend(CanCan::Ability)
|
||||||
|
end
|
||||||
|
|
||||||
|
after(:each) do
|
||||||
|
Mongoid.master.collections.select do |collection|
|
||||||
|
collection.name !~ /system/
|
||||||
|
end.each(&:drop)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should return [] when no ability is defined so no records are found" do
|
||||||
|
@model_class.accessible_by(@ability, :read).should == []
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should call where with matching ability conditions" do
|
||||||
|
@ability.can :read, @model_class, :foo => {:bar => 1}
|
||||||
|
@model_class.accessible_by(@ability, :read).should == @model_class.where(:foos => { :bar => 1 })
|
||||||
|
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
|
Loading…
Reference in New Issue
Block a user