123456789_123456789_123456789_123456789_123456789_

Module: ActiveModel::AttributeMethods

Relationships & Source Files
Namespace Children
Modules:
Extension / Inclusion / Inheritance Descendants
Included In:
Attributes, Dirty, ::ActiveRecord::AttributeMethods, ::ActiveRecord::AttributeMethods::Dirty, ::ActiveRecord::Base, ActiveRecord::InternalMetadata, ActiveRecord::SchemaMigration
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Defined in: activemodel/lib/active_model/attribute_methods.rb

Overview

Provides a way to add prefixes and suffixes to your methods as well as handling the creation of ::ActiveRecord::Base-like class methods such as table_name.

The requirements to implement AttributeMethods are to:

  • include ActiveModel::AttributeMethods in your class.

  • Call each of its methods you want to add, such as attribute_method_suffix or attribute_method_prefix.

  • Call define_attribute_methods after the other methods are called.

  • Define the various generic _attribute methods that you have declared.

  • Define an attributes method which returns a hash with each attribute name in your model as hash key and the attribute value as hash value. Hash keys must be strings.

A minimal implementation could be:

class Person
  include ActiveModel::AttributeMethods

  attribute_method_affix  prefix: 'reset_', suffix: '_to_default!'
  attribute_method_suffix '_contrived?'
  attribute_method_prefix 'clear_'
  define_attribute_methods :name

  attr_accessor :name

  def attributes
    { 'name' => @name }
  end

  private

  def attribute_contrived?(attr)
    true
  end

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

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

Constant Summary

Class Method Summary

::ActiveSupport::Concern - Extended

class_methods

Define class methods from given block.

included

Evaluate given block in context of base class, so that you can write class macros here.

prepended

Evaluate given block in context of base class, so that you can write class macros here.

Instance Method Summary

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block)

Allows access to the object attributes, which are held in the hash returned by attributes, as though they were first-class methods. So a Person class with a name attribute can for example use Person#name and Person#name= and never directly use the attributes hash – except for multiple assignments with ActiveRecord::Base#attributes=.

It’s also possible to instantiate related objects, so a Client class belonging to the clients table with a master_id foreign key can instantiate master through Client#master.

[ GitHub ]

  
# File 'activemodel/lib/active_model/attribute_methods.rb', line 464

def method_missing(method, *args, &block)
  if respond_to_without_attributes?(method, true)
    super
  else
    match = matched_attribute_method(method.to_s)
    match ? attribute_missing(match, *args, &block) : super
  end
end

DSL Calls

included

[ GitHub ]


71
72
73
74
# File 'activemodel/lib/active_model/attribute_methods.rb', line 71

included do
  class_attribute :attribute_aliases, instance_writer: false, default: {}
  class_attribute :attribute_method_matchers, instance_writer: false, default: [ ClassMethods::AttributeMethodMatcher.new ]
end

Instance Method Details

#attribute_missing(match, *args, &block)

attribute_missing is like #method_missing, but for attributes. When #method_missing is called we check to see if there is a matching attribute method. If so, we tell attribute_missing to dispatch the attribute. This method can be overloaded to customize the behavior.

[ GitHub ]

  
# File 'activemodel/lib/active_model/attribute_methods.rb', line 478

def attribute_missing(match, *args, &block)
  __send__(match.target, match.attr_name, *args, &block)
end

#respond_to?(method, include_private_methods = false) ⇒ Boolean

[ GitHub ]

  
# File 'activemodel/lib/active_model/attribute_methods.rb', line 486

def respond_to?(method, include_private_methods = false)
  if super
    true
  elsif !include_private_methods && super(method, true)
    # If we're here then we haven't found among non-private methods
    # but found among all methods. Which means that the given method is private.
    false
  else
    !matched_attribute_method(method.to_s).nil?
  end
end

#respond_to_without_attributes?

A Person instance with a name attribute can ask person.respond_to?(:name), person.respond_to?(:name=), and person.respond_to?(:name?) which will all return true.

[ GitHub ]

  
# File 'activemodel/lib/active_model/attribute_methods.rb', line 485

alias :respond_to_without_attributes? :respond_to?