Class: ActiveRecord::PredicateBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/active_record/relation/predicate_builder.rb

Overview

:nodoc:

Class Method Summary collapse

Class Method Details

.build_from_hash(engine, attributes, default_table, allow_table_name = true) ⇒ Object



3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/active_record/relation/predicate_builder.rb', line 3

def self.build_from_hash(engine, attributes, default_table, allow_table_name = true)
  predicates = attributes.map do |column, value|
    table = default_table

    if allow_table_name && value.is_a?(Hash)
      table = Arel::Table.new(column, engine)

      if value.empty?
        '1 = 2'
      else
        build_from_hash(engine, value, table, false)
      end
    else
      column = column.to_s

      if allow_table_name && column.include?('.')
        table_name, column = column.split('.', 2)
        table = Arel::Table.new(table_name, engine)
      end

      attribute = table[column]

      case value
      when ActiveRecord::Relation
        value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
        attribute.in(value.arel.ast)
      when Array, ActiveRecord::Associations::CollectionProxy
        values = value.to_a.map {|x| x.is_a?(ActiveRecord::Base) ? x.id : x}
        ranges, values = values.partition {|v| v.is_a?(Range) || v.is_a?(Arel::Relation)}

        array_predicates = ranges.map {|range| attribute.in(range)}

        if values.include?(nil)
          values = values.compact
          if values.empty?
            array_predicates << attribute.eq(nil)
          else
            array_predicates << attribute.in(values.compact).or(attribute.eq(nil))
          end
        else
          array_predicates << attribute.in(values)
        end

        array_predicates.inject {|composite, predicate| composite.or(predicate)}
      when Range, Arel::Relation
        attribute.in(value)
      when ActiveRecord::Base
        attribute.eq(value.id)
      when Class
        # FIXME: I think we need to deprecate this behavior
        attribute.eq(value.name)
      else
        attribute.eq(value)
      end
    end
  end

  predicates.flatten
end