class CanCanCan::BabySqueel::BabySqueelAdapter

Constants

ALWAYS_FALSE
ALWAYS_TRUE

Public Class Methods

for_class?(model_class) click to toggle source
# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 8
def self.for_class?(model_class)
  model_class <= ActiveRecord::Base
end
matches_condition?(subject, name, value) click to toggle source
# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 16
def self.matches_condition?(subject, name, value)
  if match_relation?(subject, name)
    matches_relation?(subject, name, value)
  elsif match_enum?(subject, name)
    matches_enum?(subject, name, value)
  else
    false
  end
end
override_condition_matching?(subject, name, _) click to toggle source
# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 12
def self.override_condition_matching?(subject, name, _)
  match_relation?(subject, name) || match_enum?(subject, name)
end

Private Class Methods

add_joins_to_scope(scope, joins, join_type = :outer) click to toggle source

Builds a relation, outer joined on the provided associations.

@param [ActiveRecord::Relation] scope The current scope to add the joins to. @param [Array<Array<Symbol>>] joins The set of associations to outer join with. @param [Symbol] join_type The type of join; defaults to outer joins. @return [ActiveRecord::Relation] The built relation.

# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 77
def self.add_joins_to_scope(scope, joins, join_type = :outer)
  joins.reduce(scope) do |result, join|
    result.joining do
      join.reduce(self) do |relation, association|
        relation = relation.__send__(association)
        relation = relation.__send__(join_type) unless join_type == :inner
        relation
      end
    end
  end
end
match_enum?(subject, name) click to toggle source

Overrides condition matching for enums.

# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 27
def self.match_enum?(subject, name)
  klass = subject.class
  klass.respond_to?(:defined_enums) && klass.defined_enums.include?(name.to_s)
end
match_relation?(subject, name) click to toggle source
# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 46
def self.match_relation?(subject, name)
  subject_attribute = subject.public_send(name)
  subject_attribute.is_a?(ActiveRecord::Relation) && !subject_attribute.loaded
end
matches_enum?(subject, name, value) click to toggle source

Overrides condition matching for enums.

# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 34
def self.matches_enum?(subject, name, value)
  # Get the mapping from enum strings to values.
  enum = subject.class.public_send(name.to_s.pluralize)

  # Get the value of the attribute as an integer.
  attribute = enum[subject.public_send(name)]

  # Check to see if the value matches the condition.
  value.is_a?(Enumerable) ? value.include?(attribute) : attribute == value
end
matches_relation?(subject, name, value) click to toggle source
# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 52
def self.matches_relation?(subject, name, value)
  relation = subject.public_send(name)
  klass = subject.class.reflect_on_association(name).klass
  join_list = nil

  scope = relation.where.has do
    expression, join_list = CanCanCan::BabySqueel::ExpressionBuilder.build(self, klass, :eq, value)
    expression
  end

  add_joins_to_scope(scope, join_list, :inner).any?
end

Public Instance Methods

database_records() click to toggle source
# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 66
def database_records
  # TODO: Handle overridden scopes.
  relation.distinct
end

Private Instance Methods

add_joins_to_scope(*args) click to toggle source

@see CanCanCan::BabySqueel::BabySqueelAdapter.add_joins_to_scope

# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 108
def add_joins_to_scope(*args)
  self.class.send(:add_joins_to_scope, *args)
end
build_accessible_by_expression(squeel) click to toggle source

This builds Squeel expression for each rule, and combines the expression with those to the left using a fold-left.

The rules provided by Cancancan are in reverse order, i.e. the lowest priority rule is first.

@param squeel The Squeel scope. @return [Array<(Squeel::Nodes::Node, Array<Array<Symbol>>)>] A tuple containing the Squeel

expression, as well as an array of joins which the Squeel expression must be joined to.
# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 120
def build_accessible_by_expression(squeel)
  @rules.reverse.reduce([ALWAYS_FALSE, []]) do |(left_expression, joins), rule|
    combine_expression_with_rule(squeel, left_expression, joins, rule)
  end
end
build_expression_from_rule(squeel, rule) click to toggle source

Builds a Squeel expression representing the rule's conditions.

@param squeel The Squeel scope. @param [CanCan::Rule] rule The rule being built. @return [Array<(Squeel::Nodes::Node, Array<Array<Symbol>>)>] A tuple containing the Squeel

expression representing the rule's conditions, as well as an array of joins which the Squeel
expression must be joined to.
# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 153
def build_expression_from_rule(squeel, rule)
  if rule.conditions.empty?
    [rule.base_behavior ? ALWAYS_TRUE : ALWAYS_FALSE, []]
  else
    comparator = rule.base_behavior ? :eq : :not_eq
    CanCanCan::BabySqueel::ExpressionBuilder.build(squeel, @model_class, comparator, rule.conditions)
  end
end
combine_expression_with_rule(squeel, left_expression, joins, rule) click to toggle source

Combines the given expression with the new rule.

@param squeel The Squeel scope. @param left_expression The Squeel expression for all preceding rules. @param [Array<Array<Symbol>>] joins An array of joins which the Squeel expression must be

joined to.

@param [CanCan::Rule] rule The rule being added. @return [Array<(Squeel::Nodes::Node, Array<Array<Symbol>>)>] A tuple containing the Squeel

expression, as well as an array of joins which the Squeel expression must be joined to.
# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 135
def combine_expression_with_rule(squeel, left_expression, joins, rule)
  right_expression, right_expression_joins = build_expression_from_rule(squeel, rule)
  operator = rule.base_behavior ? :or : :and

  expression, joins = combine_squeel_expressions(left_expression, joins, operator, right_expression,
                                                 right_expression_joins)

  squeel._scope = add_joins_to_scope(squeel._scope, joins)
  [expression, joins]
end
relation() click to toggle source

Builds a relation that expresses the set of provided rules.

The required Squeel expression is built, then the joins which are necessary to satisfy the expressions are added to the query scope.

# File lib/cancancan/baby_squeel/baby_squeel_adapter.rb, line 96
def relation
  adapter = self
  join_list = nil
  scope = @model_class.where(nil).where.has do
    expression, join_list = adapter.send(:build_accessible_by_expression, self)
    expression
  end

  add_joins_to_scope(scope, join_list)
end