Open-Source Wikis

/

Ruby on Rails

/

Packages

/

Active Model

rails/rails

Active Model

Active contributors: rafaelfranca, jeremy, dhh

Purpose

Active Model gives plain Ruby objects the same conventions an Active Record model has — validations, callbacks, dirty tracking, attribute typing, and serialization — without requiring a database. It is designed so a non-AR class (a form object, a value object, a TableLess model) can be used with Action View form helpers, JSON serializers, and validators.

Source: activemodel/lib/active_model/. ~9,000 lines of Ruby.

Directory layout

activemodel/
├── lib/
│   └── active_model/
│       ├── attribute.rb              # Single attribute representation
│       ├── attribute_set/            # Collection of attributes for a model
│       ├── attributes.rb             # The attribute DSL
│       ├── callbacks.rb              # before_*/after_*/around_* callbacks
│       ├── dirty.rb                  # Track changed attributes
│       ├── errors.rb                 # ActiveModel::Errors collection
│       ├── model.rb                  # ActiveModel::Model convenience module
│       ├── naming.rb                 # ActiveModel::Name (singular/plural/route_key)
│       ├── secure_password/          # has_secure_password (bcrypt + argon2)
│       ├── serialization.rb          # to_json, to_xml extension points
│       ├── translation.rb            # I18n integration
│       ├── type/                     # Type coercion (string, integer, decimal, etc.)
│       ├── validations/              # Built-in validators
│       ├── validations.rb            # validates / validate DSL
│       ├── validator.rb              # Base class for custom validators
│       └── api.rb                    # ActiveModel::API convenience module
├── test/
└── activemodel.gemspec

Key abstractions

Constant File Purpose
ActiveModel::Model activemodel/lib/active_model/model.rb Convenience include for naming, conversion, validations, attribute assignment
ActiveModel::API activemodel/lib/active_model/api.rb Lighter-weight version of Model for API-only objects
ActiveModel::Validations activemodel/lib/active_model/validations.rb The validates DSL
ActiveModel::Callbacks activemodel/lib/active_model/callbacks.rb Define before_save-style callbacks on plain objects
ActiveModel::Dirty activemodel/lib/active_model/dirty.rb name_changed?, changes, previous_changes
ActiveModel::Attributes activemodel/lib/active_model/attributes.rb Declare typed attributes (attribute :age, :integer)
ActiveModel::AttributeSet activemodel/lib/active_model/attribute_set/ Container for an instance's attributes
ActiveModel::Type::Value activemodel/lib/active_model/type/value.rb Base class for type coercers
ActiveModel::Errors activemodel/lib/active_model/errors.rb Validation error collection with I18n
ActiveModel::Name activemodel/lib/active_model/naming.rb User, users, user_path, etc. derivations
ActiveModel::SecurePassword activemodel/lib/active_model/secure_password.rb has_secure_password for bcrypt or argon2
ActiveModel::Serialization activemodel/lib/active_model/serialization.rb as_json, to_json, to_xml

Validations

Validations are the most-used feature. The DSL is:

class User
  include ActiveModel::Model
  attr_accessor :name, :email
  validates :name, presence: true
  validates :email, format: /@/
end

Built-in validators live in activemodel/lib/active_model/validations/:

  • presence.rb / absence.rb
  • acceptance.rb (e.g., terms-of-service checkbox)
  • confirmation.rb (password_confirmation matching)
  • inclusion.rb / exclusion.rb
  • format.rb
  • length.rb
  • numericality.rb
  • comparison.rb
  • with.rb (delegate to a custom validator)

Each is a subclass of ActiveModel::EachValidator. Custom validators inherit from ActiveModel::Validator (activemodel/lib/active_model/validator.rb).

Attributes

ActiveModel::Attributes lets a plain Ruby object declare typed attributes:

class Order
  include ActiveModel::Attributes
  attribute :total, :decimal
  attribute :placed_at, :datetime
end

Types live in activemodel/lib/active_model/type/. Each type coerces on assignment, supports serialization, and integrates with Dirty and Errors. Active Record extends this same type system in activerecord/lib/active_record/type/.

Dirty tracking

ActiveModel::Dirty provides attribute_changed?, attribute_was, changes, and previous_changes. It works on top of ActiveModel::Attributes (each attribute's underlying Attribute knows its prior value).

person.name = "Bob"
person.name_changed?    # => true
person.name_was         # => "Alice"
person.changes          # => { "name" => ["Alice", "Bob"] }

The mutation tracker in attribute_mutation_tracker.rb handles in-place mutation of mutable types (e.g., Hash / Array attributes).

Errors

ActiveModel::Errors (activemodel/lib/active_model/errors.rb) is the collection used by record.errors. It supports:

  • Per-attribute lookup (errors[:name]).
  • Full-message formatting via I18n.
  • Nested errors for has_many / has_one validations (nested_error.rb).

Action View's form helpers automatically render error messages from this collection, so any class that exposes errors works with form_with.

Secure password

has_secure_password adds password hashing to a class. By default it uses bcrypt, with optional argon2 support if the argon2 gem is loaded. Implementation in activemodel/lib/active_model/secure_password.rb. The Gemfile lists both bcrypt and argon2 with require: false so the framework doesn't depend on a binary library at load time.

Naming

ActiveModel::Naming derives "name forms" used by helpers and routes:

ActiveModel::Name.new(User)
# => #<ActiveModel::Name: name="User", singular="user", plural="users",
#                        route_key="users", param_key="user", human="User">

Action View's form_with, polymorphic_url, and most URL helpers rely on this.

Integration points

  • Active Record mixes most of Active Model into ActiveRecord::Base (activerecord/lib/active_record/base.rb).
  • Action View form helpers accept anything that responds to the Active Model lint methods.
  • Action Mailer uses ActiveModel::Naming to derive mailer view paths.
  • ActiveModel::Lint::Tests (activemodel/lib/active_model/lint.rb) is a Minitest mixin for verifying that a class implements the Active Model contract.

Entry points for modification

  • Adding a validator: subclass ActiveModel::EachValidator, place under activemodel/lib/active_model/validations/, add a test under activemodel/test/cases/validations/.
  • Adding an attribute type: subclass ActiveModel::Type::Value, register via ActiveModel::Type.register(:my_type, ::Type::MyType).
  • Adding a callback group: use define_model_callbacks from ActiveModel::Callbacks (delegates to ActiveSupport::Callbacks).

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Active Model – Ruby on Rails wiki | Factory