Skip to content

Commit

Permalink
Full update on ActiveModel documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
mikel committed Jan 31, 2010
1 parent c493370 commit a07d0f8
Show file tree
Hide file tree
Showing 10 changed files with 562 additions and 70 deletions.
211 changes: 185 additions & 26 deletions activemodel/README
@@ -1,45 +1,68 @@
= 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 callbacks to your class

class MyClass
extend ActiveModel::Callbacks
define_model_callbacks :create

def create
_run_create_callbacks do
# Your create action methods here
end
end
end

...gives you before_create, around_create and after_create class methods that
wrap your create method.

* 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
end

...gives 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
end
end

...gives 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 MyClass
class Person
include ActiveModel::Conversion
end

...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 = Person.new
Expand All @@ -52,6 +75,142 @@ functionality from the following modules:
person.name = 'robert'
person.save
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 = ActiveModel::Errors.new(self)
end

attr_accessor :name
attr_reader :errors

def validate!
errors.add(:name, "can not be nil") if name == nil
end

def ErrorsPerson.human_attribute_name(attr, options = {})
"Name"
end

end

... gives you...

person.errors.full_messages
# => ["Name Can not be nil"]
person.errors.full_messages
# => ["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

...gives 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
functions.

{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 = SerialPerson.new
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]


* Turning your object into a finite State Machine

ActiveModel::StateMachine provides a clean way to include all the methods
you need to transform your object into a finite State Machine...

light = TrafficLight.new
light.current_state #=> :red
light.change_color! #=> true
light.current_state #=> :green

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

* Integrating with Rail's internationalization (i18n) handling through
ActiveModel::Translations...

class Person
extend ActiveModel::Translation
end

{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
end
end

person = Person.new(:first_name => '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
end

class HasNameValidator < ActiveModel::Validator
def validate(record)
record.errors[:name] = "must exist" if record.name.blank?
end
end

p = ValidatorPerson.new
p.valid? #=> false
p.errors.full_messages #=> ["Name must exist"]
p.name = "Bob"
p.valid? #=> true

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

0 comments on commit a07d0f8

Please sign in to comment.