Module: ActiveModel::AttributeMethods::ClassMethods

Defined in:
lib/active_model/attribute_methods.rb

Defined Under Namespace

Classes: AttributeMethodMatcher

Instance Method Summary collapse

Instance Method Details

#alias_attribute(new_name, old_name) ⇒ Object

Allows you to make aliases for attributes.

class Person
  include ActiveModel::AttributeMethods

  attr_accessor :name
  attribute_method_suffix '_short?'
  define_attribute_methods :name

  alias_attribute :nickname, :name

  private
    def attribute_short?(attr)
      send(attr).length < 5
    end
end

person = Person.new
person.name = 'Bob'
person.name            # => "Bob"
person.nickname        # => "Bob"
person.name_short?     # => true
person.nickname_short? # => true


204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
# File 'lib/active_model/attribute_methods.rb', line 204

def alias_attribute(new_name, old_name)
  self.attribute_aliases = attribute_aliases.merge(new_name.to_s => old_name.to_s)
  ActiveSupport::CodeGenerator.batch(self, __FILE__, __LINE__) do |code_generator|
    attribute_method_matchers.each do |matcher|
      method_name = matcher.method_name(new_name).to_s
      target_name = matcher.method_name(old_name).to_s
      parameters = matcher.parameters

      mangled_name = target_name
      unless NAME_COMPILABLE_REGEXP.match?(target_name)
        mangled_name = "__temp__#{target_name.unpack1("h*")}"
      end

      code_generator.define_cached_method(method_name, as: mangled_name, namespace: :alias_attribute) do |batch|
        body = if CALL_COMPILABLE_REGEXP.match?(target_name)
          "self.#{target_name}(#{parameters || ''})"
        else
          call_args = [":'#{target_name}'"]
          call_args << parameters if parameters
          "send(#{call_args.join(", ")})"
        end

        modifier = matcher.parameters == FORWARD_PARAMETERS ? "ruby2_keywords " : ""

        batch <<
          "#{modifier}def #{mangled_name}(#{parameters || ''})" <<
          body <<
          "end"
      end
    end
  end
end

#attribute_alias(name) ⇒ Object

Returns the original name for the alias name



243
244
245
# File 'lib/active_model/attribute_methods.rb', line 243

def attribute_alias(name)
  attribute_aliases[name.to_s]
end

#attribute_alias?(new_name) ⇒ Boolean

Is new_name an alias?

Returns:

  • (Boolean)


238
239
240
# File 'lib/active_model/attribute_methods.rb', line 238

def attribute_alias?(new_name)
  attribute_aliases.key? new_name.to_s
end

#attribute_method_affix(*affixes) ⇒ Object

Declares a method available for all attributes with the given prefix and suffix. Uses method_missing and respond_to? to rewrite the method.

#{prefix}#{attr}#{suffix}(*args, &block)

to

#{prefix}attribute#{suffix}(#{attr}, *args, &block)

An #{prefix}attribute#{suffix} instance method must exist and accept at least the attr argument.

class Person
  include ActiveModel::AttributeMethods

  attr_accessor :name
  attribute_method_affix prefix: 'reset_', suffix: '_to_default!'
  define_attribute_methods :name

  private
    def reset_attribute_to_default!(attr)
      send("#{attr}=", 'Default Name')
    end
end

person = Person.new
person.name                         # => 'Gem'
person.reset_name_to_default!
person.name                         # => 'Default Name'


176
177
178
179
# File 'lib/active_model/attribute_methods.rb', line 176

def attribute_method_affix(*affixes)
  self.attribute_method_matchers += affixes.map! { |affix| AttributeMethodMatcher.new(**affix) }
  undefine_attribute_methods
end

#attribute_method_prefix(*prefixes, parameters: nil) ⇒ Object

Declares a method available for all attributes with the given prefix. Uses method_missing and respond_to? to rewrite the method.

#{prefix}#{attr}(*args, &block)

to

#{prefix}attribute(#{attr}, *args, &block)

An instance method #{prefix}attribute must exist and accept at least the attr argument.

class Person
  include ActiveModel::AttributeMethods

  attr_accessor :name
  attribute_method_prefix 'clear_'
  define_attribute_methods :name

  private
    def clear_attribute(attr)
      send("#{attr}=", nil)
    end
end

person = Person.new
person.name = 'Bob'
person.name          # => "Bob"
person.clear_name
person.name          # => nil


107
108
109
110
# File 'lib/active_model/attribute_methods.rb', line 107

def attribute_method_prefix(*prefixes, parameters: nil)
  self.attribute_method_matchers += prefixes.map! { |prefix| AttributeMethodMatcher.new(prefix: prefix, parameters: parameters) }
  undefine_attribute_methods
end

#attribute_method_suffix(*suffixes, parameters: nil) ⇒ Object

Declares a method available for all attributes with the given suffix. Uses method_missing and respond_to? to rewrite the method.

#{attr}#{suffix}(*args, &block)

to

attribute#{suffix}(#{attr}, *args, &block)

An attribute#{suffix} instance method must exist and accept at least the attr argument.

class Person
  include ActiveModel::AttributeMethods

  attr_accessor :name
  attribute_method_suffix '_short?'
  define_attribute_methods :name

  private
    def attribute_short?(attr)
      send(attr).length < 5
    end
end

person = Person.new
person.name = 'Bob'
person.name          # => "Bob"
person.name_short?   # => true


141
142
143
144
# File 'lib/active_model/attribute_methods.rb', line 141

def attribute_method_suffix(*suffixes, parameters: nil)
  self.attribute_method_matchers += suffixes.map! { |suffix| AttributeMethodMatcher.new(suffix: suffix, parameters: parameters) }
  undefine_attribute_methods
end

#define_attribute_method(attr_name, _owner: generated_attribute_methods) ⇒ Object

Declares an attribute that should be prefixed and suffixed by ActiveModel::AttributeMethods.

To use, pass an attribute name (as string or symbol). Be sure to declare define_attribute_method after you define any prefix, suffix or affix method, or they will not hook in.

class Person
  include ActiveModel::AttributeMethods

  attr_accessor :name
  attribute_method_suffix '_short?'

  # Call to define_attribute_method must appear after the
  # attribute_method_prefix, attribute_method_suffix or
  # attribute_method_affix declarations.
  define_attribute_method :name

  private
    def attribute_short?(attr)
      send(attr).length < 5
    end
end

person = Person.new
person.name = 'Bob'
person.name        # => "Bob"
person.name_short? # => true


304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/active_model/attribute_methods.rb', line 304

def define_attribute_method(attr_name, _owner: generated_attribute_methods)
  ActiveSupport::CodeGenerator.batch(_owner, __FILE__, __LINE__) do |owner|
    attribute_method_matchers.each do |matcher|
      method_name = matcher.method_name(attr_name)

      unless instance_method_already_implemented?(method_name)
        generate_method = "define_method_#{matcher.target}"

        if respond_to?(generate_method, true)
          send(generate_method, attr_name.to_s, owner: owner)
        else
          define_proxy_call(owner, method_name, matcher.target, matcher.parameters, attr_name.to_s, namespace: :active_model_proxy)
        end
      end
    end
    attribute_method_matchers_cache.clear
  end
end

#define_attribute_methods(*attr_names) ⇒ Object

Declares the attributes that should be prefixed and suffixed by ActiveModel::AttributeMethods.

To use, pass attribute names (as strings or symbols). Be sure to declare define_attribute_methods after you define any prefix, suffix, or affix methods, or they will not hook in.

class Person
  include ActiveModel::AttributeMethods

  attr_accessor :name, :age, :address
  attribute_method_prefix 'clear_'

  # Call to define_attribute_methods must appear after the
  # attribute_method_prefix, attribute_method_suffix or
  # attribute_method_affix declarations.
  define_attribute_methods :name, :age, :address

  private
    def clear_attribute(attr)
      send("#{attr}=", nil)
    end
end


270
271
272
273
274
# File 'lib/active_model/attribute_methods.rb', line 270

def define_attribute_methods(*attr_names)
  ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
    attr_names.flatten.each { |attr_name| define_attribute_method(attr_name, _owner: owner) }
  end
end

#undefine_attribute_methodsObject

Removes all the previously dynamically defined methods from the class.

class Person
  include ActiveModel::AttributeMethods

  attr_accessor :name
  attribute_method_suffix '_short?'
  define_attribute_method :name

  private
    def attribute_short?(attr)
      send(attr).length < 5
    end
end

person = Person.new
person.name = 'Bob'
person.name_short? # => true

Person.undefine_attribute_methods

person.name_short? # => NoMethodError


345
346
347
348
349
350
# File 'lib/active_model/attribute_methods.rb', line 345

def undefine_attribute_methods
  generated_attribute_methods.module_eval do
    undef_method(*instance_methods)
  end
  attribute_method_matchers_cache.clear
end