rails / activemodel /

Filename Size Date modified Message
1.2 KB
1.0 KB
5.5 KB
1.3 KB
903 B
= Active Model - defined interfaces for Rails
Prior to Rails 3.0, if a plugin or gem developer wanted to be able to have
an object interact with Action Pack helpers, it was required to either
copy chunks of code from Rails, or monkey patch entire helpers to make them
handle objects that did not look like Active Record.  This generated code
duplication and fragile applications that broke on upgrades.
Active Model is a solution for this problem.
Active Model provides a known set of interfaces that your objects can implement
to then present a common interface to the Action Pack helpers.  You can include
functionality from the following modules:

* Adding attribute magic to your objects

    Add prefixes and suffixes to defined attribute methods...
    class Person
      include ActiveModel::AttributeMethods
      attribute_method_prefix 'clear_'
      define_attribute_methods [:name, :age]
      attr_accessor :name, :age
      def clear_attribute(attr)
        send("#{attr}=", nil)
    end you clear_name, clear_age.
  {Learn more}[link:classes/ActiveModel/AttributeMethods.html]
* Adding callbacks to your objects

    class Person
      extend ActiveModel::Callbacks
      define_model_callbacks :create
      def create
        _run_create_callbacks do
          # Your create action methods here
    end you before_create, around_create and after_create class methods that
    wrap your create method.
  {Learn more}[link:classes/ActiveModel/CallBacks.html]

* For classes that already look like an Active Record object

    class Person
      include ActiveModel::Conversion
    ...returns the class itself when sent :to_model

   {Learn more}[link:classes/ActiveModel/Conversion.html]

* Tracking changes in your object

    Provides all the value tracking features implemented by ActiveRecord...
    person = # => nil
    person.changed? # => false = 'bob'
    person.changed? # => true
    person.changed # => ['name']
    person.changes # => { 'name' => [nil, 'bob'] } = 'robert'
    person.previous_changes # => {'name' => ['bob, 'robert']}
  {Learn more}[link:classes/ActiveModel/Dirty.html]

* Adding +errors+ support to your object

    Provides the error messages to allow your object to interact with Action Pack
    helpers seamlessly...
    class Person
      def initialize
        @errors =
      attr_accessor :name
      attr_reader   :errors
      def validate!
        errors.add(:name, "can not be nil") if name == nil
      def ErrorsPerson.human_attribute_name(attr, options = {})
    ... gives you...
    # => ["Name Can not be nil"]
    # => ["Name Can not be nil"]

  {Learn more}[link:classes/ActiveModel/Errors.html]

* Testing the compliance of your object

    Use ActiveModel::Lint to test the compliance of your object to the
    basic ActiveModel API...
  {Learn more}[link:classes/ActiveModel/Lint/Tests.html]

* Providing a human face to your object

    ActiveModel::Naming provides your model with the model_name convention
    and a human_name attribute...
    class NamedPerson
      extend ActiveModel::Naming
    end you...
    NamedPerson.model_name        #=> "NamedPerson"
    NamedPerson.model_name.human  #=> "Named person"

  {Learn more}[link:classes/ActiveModel/Naming.html]

* Adding observer support to your objects

    ActiveModel::Observers allows your object to implement the Observer
    pattern in a Rails App and take advantage of all the standard observer
  {Learn more}[link:classes/ActiveModel/Observer.html]

* Making your object serializable

    ActiveModel::Serialization provides a standard interface for your object
    to provide to_json or to_xml serialization...
    s =
    s.serializable_hash   # => {"name"=>nil}
    s.to_json             # => "{\"name\":null}"
    s.to_xml              # => "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<serial-person...
  {Learn more}[link:classes/ActiveModel/Serialization.html]

* Integrating with Rail's internationalization (i18n) handling through

    class Person
      extend ActiveModel::Translation
  {Learn more}[link:classes/ActiveModel/Translation.html]

* Providing a full Validation stack for your objects...

   class Person
     include ActiveModel::Validations

     attr_accessor :first_name, :last_name

     validates_each :first_name, :last_name do |record, attr, value|
       record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z

   person = => 'zoolander')
   person.valid?          #=> false

  {Learn more}[link:classes/ActiveModel/Validations.html]
* Make custom validators

   class Person
     include ActiveModel::Validations
     validates_with HasNameValidator
     attr_accessor :name
   class HasNameValidator < ActiveModel::Validator
     def validate(record)
      record.errors[:name] = "must exist" if
   p =
   p.valid?                  #=>  false
   p.errors.full_messages    #=> ["Name must exist"] = "Bob"
   p.valid?                  #=>  true

  {Learn more}[link:classes/ActiveModel/Validator.html]