allow Active Record scope to be passed as Ability conditions - closes #257
This commit is contained in:
		
							parent
							
								
									80f1ab20fb
								
							
						
					
					
						commit
						f9b181af05
					
				@ -55,7 +55,9 @@ module CanCan
 | 
				
			|||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      def database_records
 | 
					      def database_records
 | 
				
			||||||
        if @model_class.respond_to?(:where) && @model_class.respond_to?(:joins)
 | 
					        if override_scope
 | 
				
			||||||
 | 
					          override_scope
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
          @model_class.scoped(:conditions => conditions, :joins => joins)
 | 
					          @model_class.scoped(:conditions => conditions, :joins => joins)
 | 
				
			||||||
@ -64,6 +66,18 @@ module CanCan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      private
 | 
					      private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      def override_scope
 | 
				
			||||||
 | 
					        conditions = @rules.map(&:conditions).compact
 | 
				
			||||||
 | 
					        if conditions.any? { |c| c.kind_of?(ActiveRecord::Relation) }
 | 
				
			||||||
 | 
					          if conditions.size == 1
 | 
				
			||||||
 | 
					            conditions.first
 | 
				
			||||||
 | 
					          else
 | 
				
			||||||
 | 
					            rule = @rules.detect { |rule| rule.conditions.kind_of?(ActiveRecord::Relation) }
 | 
				
			||||||
 | 
					            raise Error, "Unable to merge an Active Record scope with other conditions. Instead use a hash or SQL for #{rule.actions.first} #{rule.subjects.first} ability."
 | 
				
			||||||
 | 
					          end
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      def merge_conditions(sql, conditions_hash, behavior)
 | 
					      def merge_conditions(sql, conditions_hash, behavior)
 | 
				
			||||||
        if conditions_hash.blank?
 | 
					        if conditions_hash.blank?
 | 
				
			||||||
          behavior ? true_sql : false_sql
 | 
					          behavior ? true_sql : false_sql
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@ module CanCan
 | 
				
			|||||||
  # it holds the information about a "can" call made on Ability and provides
 | 
					  # it holds the information about a "can" call made on Ability and provides
 | 
				
			||||||
  # helpful methods to determine permission checking and conditions hash generation.
 | 
					  # helpful methods to determine permission checking and conditions hash generation.
 | 
				
			||||||
  class Rule # :nodoc:
 | 
					  class Rule # :nodoc:
 | 
				
			||||||
    attr_reader :base_behavior, :actions, :conditions
 | 
					    attr_reader :base_behavior, :subjects, :actions, :conditions
 | 
				
			||||||
    attr_writer :expanded_actions
 | 
					    attr_writer :expanded_actions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # The first argument when initializing is the base_behavior which is a true/false
 | 
					    # The first argument when initializing is the base_behavior which is a true/false
 | 
				
			||||||
 | 
				
			|||||||
@ -110,10 +110,25 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
 | 
				
			|||||||
      @ability.can :read, Article, :published => true
 | 
					      @ability.can :read, Article, :published => true
 | 
				
			||||||
      @ability.can :read, Article, ["secret=?", true]
 | 
					      @ability.can :read, Article, ["secret=?", true]
 | 
				
			||||||
      article1 = Article.create!(:published => true, :secret => false)
 | 
					      article1 = Article.create!(:published => true, :secret => false)
 | 
				
			||||||
 | 
					      article2 = Article.create!(:published => true, :secret => true)
 | 
				
			||||||
 | 
					      article3 = Article.create!(:published => false, :secret => true)
 | 
				
			||||||
      article4 = Article.create!(:published => false, :secret => false)
 | 
					      article4 = Article.create!(:published => false, :secret => false)
 | 
				
			||||||
 | 
					      Article.accessible_by(@ability).should == [article1, article2, article3]
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "should allow a scope for conditions" do
 | 
				
			||||||
 | 
					      @ability.can :read, Article, Article.where(:secret => true)
 | 
				
			||||||
 | 
					      article1 = Article.create!(:secret => true)
 | 
				
			||||||
 | 
					      article2 = Article.create!(:secret => false)
 | 
				
			||||||
      Article.accessible_by(@ability).should == [article1]
 | 
					      Article.accessible_by(@ability).should == [article1]
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it "should raise an exception when trying to merge scope with other conditions" do
 | 
				
			||||||
 | 
					      @ability.can :read, Article, :published => true
 | 
				
			||||||
 | 
					      @ability.can :read, Article, Article.where(:secret => true)
 | 
				
			||||||
 | 
					      lambda { Article.accessible_by(@ability) }.should raise_error(CanCan::Error, "Unable to merge an Active Record scope with other conditions. Instead use a hash or SQL for read Article ability.")
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    it "should not allow to fetch records when ability with just block present" do
 | 
					    it "should not allow to fetch records when ability with just block present" do
 | 
				
			||||||
      @ability.can :read, Article do
 | 
					      @ability.can :read, Article do
 | 
				
			||||||
        false
 | 
					        false
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user