Module: ActiveRecord::AttributeMethods::ClassMethods

Defined in:
lib/active_record/attribute_methods.rb

Instance Method Summary collapse

Instance Method Details

#attribute_method?(attribute) ⇒ Boolean

Returns:

  • (Boolean)

121
122
123
# File 'lib/active_record/attribute_methods.rb', line 121

def attribute_method?(attribute)
  super || (table_exists? && column_names.include?(attribute.to_s.sub(/=$/, '')))
end

#attribute_methods_generated?Boolean

Returns:

  • (Boolean)

72
73
74
# File 'lib/active_record/attribute_methods.rb', line 72

def attribute_methods_generated?
  @attribute_methods_generated ||= false
end

#attribute_namesObject

Returns an array of column names as strings if it's not an abstract class and table exists. Otherwise it returns an empty array.


128
129
130
131
132
133
134
# File 'lib/active_record/attribute_methods.rb', line 128

def attribute_names
  @attribute_names ||= if !abstract_class? && table_exists?
      column_names
    else
      []
    end
end

#dangerous_attribute_method?(name) ⇒ Boolean

A method name is 'dangerous' if it is already defined by Active Record, but not by any ancestors. (So 'puts' is not dangerous but 'save' is.)

Returns:

  • (Boolean)

105
106
107
# File 'lib/active_record/attribute_methods.rb', line 105

def dangerous_attribute_method?(name)
  method_defined_within?(name, Base)
end

#define_attribute_methodsObject

Generates all the attribute related methods for columns in the database accessors, mutators and query methods.


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/active_record/attribute_methods.rb', line 38

def define_attribute_methods
  unless defined?(@attribute_methods_mutex)
    msg = "It looks like something (probably a gem/plugin) is overriding the " \
          "ActiveRecord::Base.inherited method. It is important that this hook executes so " \
          "that your models are set up correctly. A workaround has been added to stop this " \
          "causing an error in 3.2, but future versions will simply not work if the hook is " \
          "overridden. If you are using Kaminari, please upgrade as it is known to have had " \
          "this problem.\n\n"
    msg << "The following may help track down the problem:"

    meth = method(:inherited)
    if meth.respond_to?(:source_location)
      msg << " #{meth.source_location.inspect}"
    else
      msg << " #{meth.inspect}"
    end
    msg << "\n\n"

    ActiveSupport::Deprecation.warn(msg)

    @attribute_methods_mutex = Mutex.new
  end

  # Use a mutex; we don't want two thread simaltaneously trying to define
  # attribute methods.
  @attribute_methods_mutex.synchronize do
    return if attribute_methods_generated?
    superclass.define_attribute_methods unless self == base_class
    super(column_names)
    column_names.each { |name| define_external_attribute_method(name) }
    @attribute_methods_generated = true
  end
end

#generated_external_attribute_methodsObject

We will define the methods as instance methods, but will call them as singleton methods. This allows us to use method_defined? to check if the method exists, which is fast and won't give any false positives from the ancestors (because there are no ancestors).


80
81
82
# File 'lib/active_record/attribute_methods.rb', line 80

def generated_external_attribute_methods
  @generated_external_attribute_methods ||= Module.new { extend self }
end

#instance_method_already_implemented?(method_name) ⇒ Boolean

Returns:

  • (Boolean)

89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/active_record/attribute_methods.rb', line 89

def instance_method_already_implemented?(method_name)
  if dangerous_attribute_method?(method_name)
    raise DangerousAttributeError, "#{method_name} is defined by ActiveRecord"
  end

  if superclass == Base
    super
  else
    # If B < A and A defines its own attribute method, then we don't want to overwrite that.
    defined = method_defined_within?(method_name, superclass, superclass.generated_attribute_methods)
    defined && !ActiveRecord::Base.method_defined?(method_name) || super
  end
end

#method_defined_within?(name, klass, sup = klass.superclass) ⇒ Boolean

Returns:

  • (Boolean)

109
110
111
112
113
114
115
116
117
118
119
# File 'lib/active_record/attribute_methods.rb', line 109

def method_defined_within?(name, klass, sup = klass.superclass)
  if klass.method_defined?(name) || klass.private_method_defined?(name)
    if sup.method_defined?(name) || sup.private_method_defined?(name)
      klass.instance_method(name).owner != sup.instance_method(name).owner
    else
      true
    end
  else
    false
  end
end

#undefine_attribute_methodsObject


84
85
86
87
# File 'lib/active_record/attribute_methods.rb', line 84

def undefine_attribute_methods
  super
  @attribute_methods_generated = false
end