allow model adapter to override condition hash matching in Rule, also clean up Mongoid adapter and specs
This commit is contained in:
@@ -15,6 +15,17 @@ module CanCan
|
||||
false # override in subclass
|
||||
end
|
||||
|
||||
# Used to determine if this model adapter will override the matching behavior for a hash of conditions.
|
||||
# If this returns true then matches_conditions_hash? will be called. See Rule#matches_conditions_hash
|
||||
def self.override_conditions_hash_matching?(subject, conditions)
|
||||
false
|
||||
end
|
||||
|
||||
# Override if override_conditions_hash_matching? returns true
|
||||
def self.matches_conditions_hash?(subject, conditions)
|
||||
raise NotImplemented, "This model adapter does not support matching on a conditions hash."
|
||||
end
|
||||
|
||||
def initialize(model_class, rules)
|
||||
@model_class = model_class
|
||||
@rules = rules
|
||||
|
||||
@@ -5,6 +5,14 @@ module CanCan
|
||||
model_class <= Mongoid::Document
|
||||
end
|
||||
|
||||
def self.override_conditions_hash_matching?(subject, conditions)
|
||||
conditions.any? { |k,v| !k.kind_of?(Symbol) }
|
||||
end
|
||||
|
||||
def self.matches_conditions_hash?(subject, conditions)
|
||||
subject.class.where(conditions).include?(subject) # just use Mongoid's where function
|
||||
end
|
||||
|
||||
def database_records
|
||||
@model_class.where(conditions)
|
||||
end
|
||||
@@ -23,33 +31,6 @@ module CanCan
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# customize to handle Mongoid queries in ability definitions conditions
|
||||
# Mongoid Criteria are simpler to check than normal conditions hashes
|
||||
# When no conditions are given, true should be returned.
|
||||
# The default CanCan behavior relies on the fact that conditions.all? will return true when conditions is empty
|
||||
# The way ruby handles all? for empty hashes can be unexpected:
|
||||
# {}.all?{|a| a == 5}
|
||||
# => true
|
||||
# {}.all?{|a| a != 5}
|
||||
# => true
|
||||
class Rule
|
||||
def matches_conditions_hash_with_mongoid_subject?(subject, conditions = @conditions)
|
||||
if defined?(::Mongoid) && subject.class.include?(::Mongoid::Document) && conditions.any?{|k,v| !k.kind_of?(Symbol)}
|
||||
if conditions.empty?
|
||||
true
|
||||
else
|
||||
subject.class.where(conditions).include?(subject) # just use Mongoid's where function
|
||||
end
|
||||
else
|
||||
matches_conditions_hash_without_mongoid_subject? subject, conditions
|
||||
end
|
||||
end
|
||||
|
||||
# could use alias_method_chain, but it's not worth adding activesupport as a gem dependency
|
||||
alias_method :matches_conditions_hash_without_mongoid_subject?, :matches_conditions_hash?
|
||||
alias_method :matches_conditions_hash?, :matches_conditions_hash_with_mongoid_subject?
|
||||
end
|
||||
end
|
||||
|
||||
# simplest way to add `accessible_by` to all Mongoid Documents
|
||||
|
||||
@@ -88,19 +88,31 @@ module CanCan
|
||||
@subjects.any? { |sub| sub.kind_of?(Module) && (subject.kind_of?(sub) || subject.class.to_s == sub.to_s || subject.kind_of?(Module) && subject.ancestors.include?(sub)) }
|
||||
end
|
||||
|
||||
# Checks if the given subject matches the given conditions hash.
|
||||
# This behavior can be overriden by a model adapter by defining two class methods:
|
||||
# override_matching_for_conditions?(subject, conditions) and
|
||||
# matches_conditions_hash?(subject, conditions)
|
||||
def matches_conditions_hash?(subject, conditions = @conditions)
|
||||
conditions.all? do |name, value|
|
||||
attribute = subject.send(name)
|
||||
if value.kind_of?(Hash)
|
||||
if attribute.kind_of? Array
|
||||
attribute.any? { |element| matches_conditions_hash? element, value }
|
||||
else
|
||||
matches_conditions_hash? attribute, value
|
||||
end
|
||||
elsif value.kind_of?(Array) || value.kind_of?(Range)
|
||||
value.include? attribute
|
||||
if conditions.empty?
|
||||
true
|
||||
else
|
||||
if model_adapter(subject).override_conditions_hash_matching? subject, conditions
|
||||
model_adapter(subject).matches_conditions_hash? subject, conditions
|
||||
else
|
||||
attribute == value
|
||||
conditions.all? do |name, value|
|
||||
attribute = subject.send(name)
|
||||
if value.kind_of?(Hash)
|
||||
if attribute.kind_of? Array
|
||||
attribute.any? { |element| matches_conditions_hash? element, value }
|
||||
else
|
||||
matches_conditions_hash? attribute, value
|
||||
end
|
||||
elsif value.kind_of?(Array) || value.kind_of?(Range)
|
||||
value.include? attribute
|
||||
else
|
||||
attribute == value
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -117,5 +129,9 @@ module CanCan
|
||||
@block.call(action, subject.class, subject, *extra_args)
|
||||
end
|
||||
end
|
||||
|
||||
def model_adapter(subject)
|
||||
ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user