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)


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

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

:nodoc:



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) # :nodoc:
  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)


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

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"]


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

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)


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

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)


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

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
125
# 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

    generate_alias_attributes

    @attribute_methods_generated = true
  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:



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

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)


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

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)


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

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)


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

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:



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

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