Module: ActiveRecord::AttributeMethods::ClassMethods

Defined in:
lib/active_record/attribute_methods.rb

Instance Method Summary collapse

Instance Method Details

#_has_attribute?(attr_name) ⇒ Boolean

:nodoc:

Returns:

  • (Boolean)


259
260
261
# File 'lib/active_record/attribute_methods.rb', line 259

def _has_attribute?(attr_name) # :nodoc:
  attribute_types.key?(attr_name)
end

#alias_attribute(new_name, old_name) ⇒ Object

Allows you to make aliases for attributes.

class Person < ActiveRecord::Base
  alias_attribute :nickname, :name
end

person = Person.create(name: 'Bob')
person.name     # => "Bob"
person.nickname # => "Bob"

The alias can also be used for querying:

Person.where(nickname: "Bob")
# SELECT "people".* FROM "people" WHERE "people"."name" = "Bob"


66
67
68
69
70
71
72
73
74
# File 'lib/active_record/attribute_methods.rb', line 66

def alias_attribute(new_name, old_name)
  super

  if @alias_attributes_mass_generated
    ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
      generate_alias_attribute_methods(code_generator, new_name, old_name)
    end
  end
end

#alias_attribute_method_definition(code_generator, pattern, new_name, old_name) ⇒ Object



87
88
89
90
91
92
93
94
95
96
# File 'lib/active_record/attribute_methods.rb', line 87

def alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
  old_name = old_name.to_s

  if !abstract_class? && !has_attribute?(old_name)
    raise ArgumentError, "#{self.name} model aliases `#{old_name}`, but `#{old_name}` is not an attribute. " \
      "Use `alias_method :#{new_name}, :#{old_name}` or define the method manually."
  else
    define_attribute_method_pattern(pattern, old_name, owner: code_generator, as: new_name, override: true)
  end
end

#attribute_method?(attribute) ⇒ Boolean

Returns true if attribute is an attribute method and table exists, false otherwise.

class Person < ActiveRecord::Base
end

Person.attribute_method?('name')   # => true
Person.attribute_method?(:age=)    # => true
Person.attribute_method?(:nothing) # => false

Returns:

  • (Boolean)


223
224
225
# File 'lib/active_record/attribute_methods.rb', line 223

def attribute_method?(attribute)
  super || (table_exists? && column_names.include?(attribute.to_s.delete_suffix("=")))
end

#attribute_methods_generated?Boolean

:nodoc:

Returns:

  • (Boolean)


98
99
100
# File 'lib/active_record/attribute_methods.rb', line 98

def attribute_methods_generated? # :nodoc:
  @attribute_methods_generated
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.

class Person < ActiveRecord::Base
end

Person.attribute_names
# => ["id", "created_at", "updated_at", "name", "age"]


235
236
237
238
239
240
241
# File 'lib/active_record/attribute_methods.rb', line 235

def attribute_names
  @attribute_names ||= if !abstract_class? && table_exists?
    attribute_types.keys
  else
    []
  end.freeze
end

#dangerous_attribute_method?(name) ⇒ Boolean

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

Returns:

  • (Boolean)


182
183
184
# File 'lib/active_record/attribute_methods.rb', line 182

def dangerous_attribute_method?(name) # :nodoc:
  ::ActiveRecord::AttributeMethods.dangerous_attribute_methods.include?(name.to_s)
end

#dangerous_class_method?(method_name) ⇒ Boolean

A class method is ‘dangerous’ if it is already (re)defined by Active Record, but not by any ancestors. (So ‘puts’ is not dangerous but ‘new’ is.)

Returns:

  • (Boolean)


200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/active_record/attribute_methods.rb', line 200

def dangerous_class_method?(method_name)
  return true if RESTRICTED_CLASS_METHODS.include?(method_name.to_s)

  if Base.respond_to?(method_name, true)
    if Object.respond_to?(method_name, true)
      Base.method(method_name).owner != Object.method(method_name).owner
    else
      true
    end
  else
    false
  end
end

#define_attribute_methodsObject

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



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/active_record/attribute_methods.rb', line 104

def define_attribute_methods # :nodoc:
  return false if @attribute_methods_generated
  # Use a mutex; we don't want two threads simultaneously trying to define
  # attribute methods.
  GeneratedAttributeMethods::LOCK.synchronize do
    return false if @attribute_methods_generated

    superclass.define_attribute_methods unless base_class?

    unless abstract_class?
      load_schema
      super(attribute_names)
      alias_attribute :id_value, :id if _has_attribute?("id")
    end

    @attribute_methods_generated = true

    generate_alias_attributes
  end
  true
end

#eagerly_generate_alias_attribute_methods(_new_name, _old_name) ⇒ Object

:nodoc:



76
77
78
# File 'lib/active_record/attribute_methods.rb', line 76

def eagerly_generate_alias_attribute_methods(_new_name, _old_name) # :nodoc:
  # alias attributes in Active Record are lazily generated
end

#generate_alias_attribute_methods(code_generator, new_name, old_name) ⇒ Object

:nodoc:



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

def generate_alias_attribute_methods(code_generator, new_name, old_name) # :nodoc:
  attribute_method_patterns.each do |pattern|
    alias_attribute_method_definition(code_generator, pattern, new_name, old_name)
  end
  attribute_method_patterns_cache.clear
end

#generate_alias_attributesObject

:nodoc:



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/active_record/attribute_methods.rb', line 126

def generate_alias_attributes # :nodoc:
  superclass.generate_alias_attributes unless superclass == Base

  return if @alias_attributes_mass_generated

  ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |code_generator|
    aliases_by_attribute_name.each do |old_name, new_names|
      new_names.each do |new_name|
        generate_alias_attribute_methods(code_generator, new_name, old_name)
      end
    end
  end

  @alias_attributes_mass_generated = true
end

#has_attribute?(attr_name) ⇒ Boolean

Returns true if the given attribute exists, otherwise false.

class Person < ActiveRecord::Base
  alias_attribute :new_name, :name
end

Person.has_attribute?('name')     # => true
Person.has_attribute?('new_name') # => true
Person.has_attribute?(:age)       # => true
Person.has_attribute?(:nothing)   # => false

Returns:

  • (Boolean)


253
254
255
256
257
# File 'lib/active_record/attribute_methods.rb', line 253

def has_attribute?(attr_name)
  attr_name = attr_name.to_s
  attr_name = attribute_aliases[attr_name] || attr_name
  attribute_types.key?(attr_name)
end

#initialize_generated_modulesObject

:nodoc:



42
43
44
45
46
47
48
49
50
# File 'lib/active_record/attribute_methods.rb', line 42

def initialize_generated_modules # :nodoc:
  @generated_attribute_methods = const_set(:GeneratedAttributeMethods, GeneratedAttributeMethods.new)
  private_constant :GeneratedAttributeMethods
  @attribute_methods_generated = false
  @alias_attributes_mass_generated = false
  include @generated_attribute_methods

  super
end

#instance_method_already_implemented?(method_name) ⇒ Boolean

Raises an ActiveRecord::DangerousAttributeError exception when an Active Record method is defined in the model, otherwise false.

class Person < ActiveRecord::Base
  def save
    'already defined by Active Record'
  end
end

Person.instance_method_already_implemented?(:save)
# => ActiveRecord::DangerousAttributeError: save is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name.

Person.instance_method_already_implemented?(:name)
# => false

Returns:

  • (Boolean)


164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/active_record/attribute_methods.rb', line 164

def instance_method_already_implemented?(method_name)
  if dangerous_attribute_method?(method_name)
    raise DangerousAttributeError, "#{method_name} is defined by Active Record. Check to make sure that you don't have an attribute or method with the same name."
  end

  if superclass == Base
    super
  else
    # If ThisClass < ... < SomeSuperClass < ... < Base and SomeSuperClass
    # defines its own attribute method, then we don't want to override that.
    defined = method_defined_within?(method_name, superclass, Base) &&
      ! superclass.instance_method(method_name).owner.is_a?(GeneratedAttributeMethods)
    defined || super
  end
end

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

:nodoc:

Returns:

  • (Boolean)


186
187
188
189
190
191
192
193
194
195
196
# File 'lib/active_record/attribute_methods.rb', line 186

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

#undefine_attribute_methodsObject

:nodoc:



142
143
144
145
146
147
148
# File 'lib/active_record/attribute_methods.rb', line 142

def undefine_attribute_methods # :nodoc:
  GeneratedAttributeMethods::LOCK.synchronize do
    super if @attribute_methods_generated
    @attribute_methods_generated = false
    @alias_attributes_mass_generated = false
  end
end