123456789_123456789_123456789_123456789_123456789_

Module: ActiveModel::AttributeMethods

Relationships & Source Files
Namespace Children
Modules:
Extension / Inclusion / Inheritance Descendants
Included In:
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.

append_features, prepend_features

Instance Method Summary

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method)

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 479

def method_missing(method, ...)
  if respond_to_without_attributes?(method, true)
    super
  else
    match = matched_attribute_method(method.name)
    match ? attribute_missing(match, ...) : super
  end
end

DSL Calls

included

[ GitHub ]


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

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

Instance Method Details

#_read_attribute(attr) (private)

[ GitHub ]

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

def _read_attribute(attr)
  __send__(attr)
end

#attribute_method?(attr_name) ⇒ Boolean (private)

[ GitHub ]

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

def attribute_method?(attr_name)
  respond_to_without_attributes?(:attributes) && attributes.include?(attr_name)
end

#attribute_missing(match)

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 492

def attribute_missing(match, ...)
  __send__(match.proxy_target, match.attr_name, ...)
end

#matched_attribute_method(method_name) (private)

Returns a struct representing the matching attribute method. The struct’s attributes are prefix, base and suffix.

[ GitHub ]

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

def matched_attribute_method(method_name)
  matches = self.class.send(:attribute_method_patterns_matching, method_name)
  matches.detect { |match| attribute_method?(match.attr_name) }
end

#missing_attribute(attr_name, stack) (private)

[ GitHub ]

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

def missing_attribute(attr_name, stack)
  raise ActiveModel::MissingAttributeError, "missing attribute '#{attr_name}' for #{self.class}", stack
end

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

[ GitHub ]

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

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 499

alias :respond_to_without_attributes? :respond_to?