README in activemodel-3.0.0.beta4 vs README in activemodel-3.0.pre

- old
+ new

@@ -1,205 +1,21 @@ -= 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: +Active Model +============== -* Adding attribute magic to your objects +Totally experimental library that aims to extract common model mixins from +ActiveRecord for use in ActiveResource (and other similar libraries). +This is in a very rough state (no autotest or spec rake tasks set up yet), +so please excuse the mess. - 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 +Here's what I plan to extract: + * ActiveModel::Observing + * ActiveModel::Callbacks + * ActiveModel::Validations - 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 ActiveResource params and ActiveRecord options + * ActiveModel::Scoping -* For classes that already look like an Active Record object + # to_json, to_xml, etc + * ActiveModel::Serialization - 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 - person.name # => nil - person.changed? # => false - person.name = 'bob' - person.changed? # => true - person.changed # => ['name'] - person.changes # => { 'name' => [nil, 'bob'] } - 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] - -* 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] +I'm trying to keep ActiveRecord compatibility where possible, but I'm +annotating the spots where I'm diverging a bit. \ No newline at end of file