Class: CanCan::ModelAdapters::ActiveRecordAdapter

Inherits:
AbstractAdapter show all
Defined in:
lib/cancan/model_adapters/active_record_adapter.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from AbstractAdapter

adapter_class, find, inherited, #initialize, matches_conditions_hash?, override_conditions_hash_matching?

Constructor Details

This class inherits a constructor from CanCan::ModelAdapters::AbstractAdapter

Class Method Details

.for_class?(model_class) ⇒ Boolean

Returns:

  • (Boolean)


4
5
6
# File 'lib/cancan/model_adapters/active_record_adapter.rb', line 4

def self.for_class?(model_class)
  model_class <= ActiveRecord::Base
end

.matches_condition?(subject, name, value) ⇒ Boolean

Returns:

  • (Boolean)


12
13
14
15
16
17
18
19
20
21
# File 'lib/cancan/model_adapters/active_record_adapter.rb', line 12

def self.matches_condition?(subject, name, value)
  subject_value = subject.send(name.column)
  if name.method.to_s.ends_with? "_any"
    value.any? { |v| meta_where_match? subject_value, name.method.to_s.sub("_any", ""), v }
  elsif name.method.to_s.ends_with? "_all"
    value.all? { |v| meta_where_match? subject_value, name.method.to_s.sub("_all", ""), v }
  else
    meta_where_match? subject_value, name.method, value
  end
end

.meta_where_match?(subject_value, method, value) ⇒ Boolean

Returns:

  • (Boolean)


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/cancan/model_adapters/active_record_adapter.rb', line 23

def self.meta_where_match?(subject_value, method, value)
  case method.to_sym
  when :eq      then subject_value == value
  when :not_eq  then subject_value != value
  when :in      then value.include?(subject_value)
  when :not_in  then !value.include?(subject_value)
  when :lt      then subject_value < value
  when :lteq    then subject_value <= value
  when :gt      then subject_value > value
  when :gteq    then subject_value >= value
  when :matches then subject_value =~ Regexp.new("^" + Regexp.escape(value).gsub("%", ".*") + "$", true)
  when :does_not_match then !meta_where_match?(subject_value, :matches, value)
  else raise NotImplemented, "The #{method} MetaWhere condition is not supported."
  end
end

.override_condition_matching?(subject, name, value) ⇒ Boolean

Returns:

  • (Boolean)


8
9
10
# File 'lib/cancan/model_adapters/active_record_adapter.rb', line 8

def self.override_condition_matching?(subject, name, value)
  name.kind_of?(MetaWhere::Column) if defined? MetaWhere
end

Instance Method Details

#conditionsObject

Returns conditions intended to be used inside a database query. Normally you will not call this method directly, but instead go through ModelAdditions#accessible_by.

If there is only one “can” definition, a hash of conditions will be returned matching the one defined.

can :manage, User, :id => 1
query(:manage, User).conditions # => { :id => 1 }

If there are multiple “can” definitions, a SQL string will be returned to handle complex cases.

can :manage, User, :id => 1
can :manage, User, :manager_id => 1
cannot :manage, User, :self_managed => true
query(:manage, User).conditions # => "not (self_managed = 't') AND ((manager_id = 1) OR (id = 1))"


54
55
56
57
58
59
60
61
62
63
# File 'lib/cancan/model_adapters/active_record_adapter.rb', line 54

def conditions
  if @rules.size == 1 && @rules.first.base_behavior
    # Return the conditions directly if there's just one definition
    tableized_conditions(@rules.first.conditions).dup
  else
    @rules.reverse.inject(false_sql) do |sql, rule|
      merge_conditions(sql, tableized_conditions(rule.conditions).dup, rule.base_behavior)
    end
  end
end

#database_recordsObject



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/cancan/model_adapters/active_record_adapter.rb', line 99

def database_records
  if override_scope
    @model_class.scoped.merge(override_scope)
  elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins)
    mergeable_conditions = @rules.select {|rule| rule.unmergeable? }.blank?
    if mergeable_conditions
      @model_class.where(conditions).joins(joins)
    else
      @model_class.where(*(@rules.map(&:conditions))).joins(joins)
    end
  else
    @model_class.scoped(:conditions => conditions, :joins => joins)
  end
end

#joinsObject

Returns the associations used in conditions for the :joins option of a search. See ModelAdditions#accessible_by



91
92
93
94
95
96
97
# File 'lib/cancan/model_adapters/active_record_adapter.rb', line 91

def joins
  joins_hash = {}
  @rules.each do |rule|
    merge_joins(joins_hash, rule.associations_hash)
  end
  clean_joins(joins_hash) unless joins_hash.empty?
end

#tableized_conditions(conditions, model_class = @model_class) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/cancan/model_adapters/active_record_adapter.rb', line 65

def tableized_conditions(conditions, model_class = @model_class)
  return conditions unless conditions.kind_of? Hash
  conditions.inject({}) do |result_hash, (name, value)|
    if value.kind_of? Hash
      value = value.dup
      association_class = model_class.reflect_on_association(name).class_name.constantize
      nested = value.inject({}) do |nested,(k,v)|
        if v.kind_of? Hash
          value.delete(k)
          nested[k] = v
        else
          name = model_class.reflect_on_association(name).table_name.to_sym
          result_hash[name] = value
        end
        nested
      end
      result_hash.merge!(tableized_conditions(nested,association_class))
    else
      result_hash[name] = value
    end
    result_hash
  end
end