merging master into 2.0
This commit is contained in:
commit
e24d5d146b
|
@ -1,3 +1,26 @@
|
||||||
|
1.6.5 (May 18, 2011)
|
||||||
|
|
||||||
|
* pass action and subject through AccessDenied exception when :through isn't found - issue #366
|
||||||
|
|
||||||
|
* many Mongoid adapter improvements (thanks rahearn, cardagin) - issues #363, #352, #343
|
||||||
|
|
||||||
|
* allow :through option to work with private controller methods - issue #360
|
||||||
|
|
||||||
|
* ensure Mongoid::Document is defined before loading Mongoid adapter - issue #359
|
||||||
|
|
||||||
|
* many DataMapper adapter improvements (thanks emmanuel) - issue #355
|
||||||
|
|
||||||
|
* handle checking nil attributes through associations (thanks thatothermitch) - issue #330
|
||||||
|
|
||||||
|
* improve scope merging - issue #328
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
1.6.4 (March 29, 2011)
|
||||||
|
|
||||||
|
* Fixed mongoid 'or' error - see issue #322
|
||||||
|
|
||||||
|
|
||||||
1.6.3 (March 25, 2011)
|
1.6.3 (March 25, 2011)
|
||||||
|
|
||||||
* Make sure ActiveRecord::Relation is defined before checking conditions against it so Rails 2 is supported again - see issue #312
|
* Make sure ActiveRecord::Relation is defined before checking conditions against it so Rails 2 is supported again - see issue #312
|
||||||
|
|
|
@ -10,4 +10,4 @@ require 'cancan/model_adapters/abstract_adapter'
|
||||||
require 'cancan/model_adapters/default_adapter'
|
require 'cancan/model_adapters/default_adapter'
|
||||||
require 'cancan/model_adapters/active_record_adapter' if defined? ActiveRecord
|
require 'cancan/model_adapters/active_record_adapter' if defined? ActiveRecord
|
||||||
require 'cancan/model_adapters/data_mapper_adapter' if defined? DataMapper
|
require 'cancan/model_adapters/data_mapper_adapter' if defined? DataMapper
|
||||||
require 'cancan/model_adapters/mongoid_adapter' if defined? Mongoid
|
require 'cancan/model_adapters/mongoid_adapter' if defined?(Mongoid) && defined?(Mongoid::Document)
|
||||||
|
|
|
@ -290,7 +290,7 @@ module CanCan
|
||||||
|
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
base.extend ClassMethods
|
base.extend ClassMethods
|
||||||
base.helper_method :can?, :cannot?
|
base.helper_method :can?, :cannot?, :current_ability
|
||||||
end
|
end
|
||||||
|
|
||||||
# Raises a CanCan::Unauthorized exception if the current_ability cannot
|
# Raises a CanCan::Unauthorized exception if the current_ability cannot
|
||||||
|
|
|
@ -165,7 +165,7 @@ module CanCan
|
||||||
elsif @options[:shallow]
|
elsif @options[:shallow]
|
||||||
resource_class
|
resource_class
|
||||||
else
|
else
|
||||||
raise Unauthorized # maybe this should be a record not found error instead?
|
raise Unauthorized.new(nil, authorization_action, @params[:controller].to_sym) # maybe this should be a record not found error instead?
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
resource_class
|
resource_class
|
||||||
|
@ -184,7 +184,7 @@ module CanCan
|
||||||
def fetch_parent(name)
|
def fetch_parent(name)
|
||||||
if @controller.instance_variable_defined? "@#{name}"
|
if @controller.instance_variable_defined? "@#{name}"
|
||||||
@controller.instance_variable_get("@#{name}")
|
@controller.instance_variable_get("@#{name}")
|
||||||
elsif @controller.respond_to? name
|
elsif @controller.respond_to?(name, true)
|
||||||
@controller.send(name)
|
@controller.send(name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -87,7 +87,7 @@ module CanCan
|
||||||
|
|
||||||
def database_records
|
def database_records
|
||||||
if override_scope
|
if override_scope
|
||||||
override_scope
|
@model_class.scoped.merge(override_scope)
|
||||||
elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins)
|
elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins)
|
||||||
@model_class.where(conditions).joins(joins)
|
@model_class.where(conditions).joins(joins)
|
||||||
else
|
else
|
||||||
|
|
|
@ -10,23 +10,22 @@ module CanCan
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.matches_conditions_hash?(subject, conditions)
|
def self.matches_conditions_hash?(subject, conditions)
|
||||||
subject.class.all(:conditions => conditions).include?(subject) # TODO don't use a database query here for performance and other instances
|
collection = DataMapper::Collection.new(subject.query, [ subject ])
|
||||||
|
!!collection.first(conditions)
|
||||||
end
|
end
|
||||||
|
|
||||||
def database_records
|
def database_records
|
||||||
scope = @model_class.all(:conditions => ["0=1"])
|
scope = @model_class.all(:conditions => ["0 = 1"])
|
||||||
conditions.each do |condition|
|
cans, cannots = @rules.partition { |r| r.base_behavior }
|
||||||
scope += @model_class.all(:conditions => condition)
|
return scope if cans.empty?
|
||||||
end
|
# apply unions first, then differences. this mean cannot overrides can
|
||||||
|
cans.each { |r| scope += @model_class.all(:conditions => r.conditions) }
|
||||||
|
cannots.each { |r| scope -= @model_class.all(:conditions => r.conditions) }
|
||||||
scope
|
scope
|
||||||
end
|
end
|
||||||
|
end # class DataMapper
|
||||||
def conditions
|
end # module ModelAdapters
|
||||||
@rules.map(&:conditions)
|
end # module CanCan
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
DataMapper::Model.class_eval do
|
DataMapper::Model.class_eval do
|
||||||
include CanCan::ModelAdditions::ClassMethods
|
include CanCan::ModelAdditions::ClassMethods
|
||||||
|
|
|
@ -6,7 +6,14 @@ module CanCan
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.override_conditions_hash_matching?(subject, conditions)
|
def self.override_conditions_hash_matching?(subject, conditions)
|
||||||
conditions.any? { |k,v| !k.kind_of?(Symbol) }
|
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
|
end
|
||||||
|
|
||||||
def self.matches_conditions_hash?(subject, conditions)
|
def self.matches_conditions_hash?(subject, conditions)
|
||||||
|
@ -16,16 +23,22 @@ module CanCan
|
||||||
end
|
end
|
||||||
|
|
||||||
def database_records
|
def database_records
|
||||||
if @rules.size == 0
|
if @rules.size == 0
|
||||||
@model_class.where(:_id => {'$exists' => false, '$type' => 7}) # return no records in Mongoid
|
@model_class.where(:_id => {'$exists' => false, '$type' => 7}) # return no records in Mongoid
|
||||||
|
elsif @rules.size == 1 && @rules[0].conditions.is_a?(Mongoid::Criteria)
|
||||||
|
@rules[0].conditions
|
||||||
else
|
else
|
||||||
@rules.inject(@model_class.all) do |records, rule|
|
# we only need to process can rules if
|
||||||
if rule.conditions.empty?
|
# there are no rules with empty conditions
|
||||||
records
|
rules = @rules.reject { |rule| rule.conditions.empty? }
|
||||||
elsif rule.base_behavior
|
process_can_rules = @rules.count == rules.count
|
||||||
records.or(rule.conditions)
|
rules.inject(@model_class.all) do |records, rule|
|
||||||
|
if process_can_rules && rule.base_behavior
|
||||||
|
records.or rule.conditions
|
||||||
|
elsif !rule.base_behavior
|
||||||
|
records.excludes rule.conditions
|
||||||
else
|
else
|
||||||
records.excludes(rule.conditions)
|
records
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -37,4 +50,4 @@ end
|
||||||
# simplest way to add `accessible_by` to all Mongoid Documents
|
# simplest way to add `accessible_by` to all Mongoid Documents
|
||||||
module Mongoid::Document::ClassMethods
|
module Mongoid::Document::ClassMethods
|
||||||
include CanCan::ModelAdditions::ClassMethods
|
include CanCan::ModelAdditions::ClassMethods
|
||||||
end
|
end
|
||||||
|
|
|
@ -125,7 +125,7 @@ module CanCan
|
||||||
if attribute.kind_of? Array
|
if attribute.kind_of? Array
|
||||||
attribute.any? { |element| matches_conditions_hash? element, value }
|
attribute.any? { |element| matches_conditions_hash? element, value }
|
||||||
else
|
else
|
||||||
matches_conditions_hash? attribute, value
|
attribute && matches_conditions_hash?(attribute, value)
|
||||||
end
|
end
|
||||||
elsif value.kind_of?(Array) || value.kind_of?(Range)
|
elsif value.kind_of?(Array) || value.kind_of?(Range)
|
||||||
value.include? attribute
|
value.include? attribute
|
||||||
|
|
|
@ -283,6 +283,13 @@ describe CanCan::Ability do
|
||||||
@ability.should be_fully_authorized(:update, :ranges)
|
@ability.should be_fully_authorized(:update, :ranges)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should not match subjects return nil for methods that must match nested a nested conditions hash" do
|
||||||
|
mock(object_with_foo = Object.new).foo { :bar }
|
||||||
|
@ability.can :read, :arrays, :first => { :foo => :bar }
|
||||||
|
@ability.can?(:read, [object_with_foo]).should be_true
|
||||||
|
@ability.can?(:read, []).should be_false
|
||||||
|
end
|
||||||
|
|
||||||
it "is not fully authorized when attributes are required but not checked in update/create actions" do
|
it "is not fully authorized when attributes are required but not checked in update/create actions" do
|
||||||
@ability.can :access, :users, :name
|
@ability.can :access, :users, :name
|
||||||
@ability.authorize! :update, :users
|
@ability.authorize! :update, :users
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe CanCan::ControllerAdditions do
|
||||||
@controller = @controller_class.new
|
@controller = @controller_class.new
|
||||||
stub(@controller).params { @params }
|
stub(@controller).params { @params }
|
||||||
stub(@controller).current_user { :current_user }
|
stub(@controller).current_user { :current_user }
|
||||||
mock(@controller_class).helper_method(:can?, :cannot?)
|
mock(@controller_class).helper_method(:can?, :cannot?, :current_ability)
|
||||||
@controller_class.send(:include, CanCan::ControllerAdditions)
|
@controller_class.send(:include, CanCan::ControllerAdditions)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -237,7 +237,10 @@ describe CanCan::ControllerResource do
|
||||||
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
resource = CanCan::ControllerResource.new(@controller, :through => :category)
|
||||||
lambda {
|
lambda {
|
||||||
resource.load_resource
|
resource.load_resource
|
||||||
}.should raise_error(CanCan::Unauthorized)
|
}.should raise_error(CanCan::Unauthorized) { |exception|
|
||||||
|
exception.action.should == :show
|
||||||
|
exception.subject.should == :projects
|
||||||
|
}
|
||||||
@controller.instance_variable_get(:@project).should be_nil
|
@controller.instance_variable_get(:@project).should be_nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,15 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
|
||||||
Article.accessible_by(@ability).should == [article1]
|
Article.accessible_by(@ability).should == [article1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should fetch only associated records when using with a scope for conditions" do
|
||||||
|
@ability.can :read, :articles, Article.where(:secret => true)
|
||||||
|
category1 = Category.create!(:visible => false)
|
||||||
|
category2 = Category.create!(:visible => true)
|
||||||
|
article1 = Article.create!(:secret => true, :category => category1)
|
||||||
|
article2 = Article.create!(:secret => true, :category => category2)
|
||||||
|
category1.articles.accessible_by(@ability).should == [article1]
|
||||||
|
end
|
||||||
|
|
||||||
it "should raise an exception when trying to merge scope with other conditions" do
|
it "should raise an exception when trying to merge scope with other conditions" do
|
||||||
@ability.can :read, :articles, :published => true
|
@ability.can :read, :articles, :published => true
|
||||||
@ability.can :read, :articles, Article.where(:secret => true)
|
@ability.can :read, :articles, Article.where(:secret => true)
|
||||||
|
|
|
@ -42,6 +42,15 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
|
||||||
@ability.should be_able_to(:read, model)
|
@ability.should be_able_to(:read, model)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should be able to read hashes when field is array" do
|
||||||
|
one_to_three = MongoidProject.create(:numbers => ['one', 'two', 'three'])
|
||||||
|
two_to_five = MongoidProject.create(:numbers => ['two', 'three', 'four', 'five'])
|
||||||
|
|
||||||
|
@ability.can :foo, :mongoid_projects, :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
|
it "should return [] when no ability is defined so no records are found" do
|
||||||
MongoidProject.create(:title => 'Sir')
|
MongoidProject.create(:title => 'Sir')
|
||||||
MongoidProject.create(:title => 'Lord')
|
MongoidProject.create(:title => 'Lord')
|
||||||
|
@ -59,6 +68,15 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
|
||||||
MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
|
MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should be able to mix empty conditions and hashes" do
|
||||||
|
@ability.can :read, :mongoid_projects
|
||||||
|
@ability.can :read, :mongoid_projects, :title => 'Sir'
|
||||||
|
sir = MongoidProject.create(:title => 'Sir')
|
||||||
|
lord = MongoidProject.create(:title => 'Lord')
|
||||||
|
|
||||||
|
MongoidProject.accessible_by(@ability, :read).count.should == 2
|
||||||
|
end
|
||||||
|
|
||||||
it "should return everything when the defined ability is access all" do
|
it "should return everything when the defined ability is access all" do
|
||||||
@ability.can :access, :all
|
@ability.can :access, :all
|
||||||
sir = MongoidProject.create(:title => 'Sir')
|
sir = MongoidProject.create(:title => 'Sir')
|
||||||
|
@ -68,6 +86,14 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
|
||||||
MongoidProject.accessible_by(@ability, :read).entries.should == [sir, lord, dude]
|
MongoidProject.accessible_by(@ability, :read).entries.should == [sir, lord, dude]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "should allow a scope for conditions" do
|
||||||
|
@ability.can :read, :mongoid_projects, MongoidProject.where(:title => 'Sir')
|
||||||
|
sir = MongoidProject.create(:title => 'Sir')
|
||||||
|
lord = MongoidProject.create(:title => 'Lord')
|
||||||
|
dude = MongoidProject.create(:title => 'Dude')
|
||||||
|
|
||||||
|
MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
|
||||||
|
end
|
||||||
|
|
||||||
describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do
|
describe "Mongoid::Criteria where clause Symbol extensions using MongoDB expressions" do
|
||||||
it "should handle :field.in" do
|
it "should handle :field.in" do
|
||||||
|
|
Loading…
Reference in New Issue
Block a user