aboutsummaryrefslogtreecommitdiffstats
path: root/activemodel
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2010-01-17 03:26:20 +0530
committerPratik Naik <pratiknaik@gmail.com>2010-01-17 03:26:20 +0530
commitdba196cb7f8d34b93f6872e4a43737bb52019065 (patch)
tree97a2f784a2ec2bfae4f960af56a9280dad6f7774 /activemodel
parent6e3bee6cf1f0d2684152292db0a8b757249824fd (diff)
downloadrails-dba196cb7f8d34b93f6872e4a43737bb52019065.tar.gz
rails-dba196cb7f8d34b93f6872e4a43737bb52019065.tar.bz2
rails-dba196cb7f8d34b93f6872e4a43737bb52019065.zip
Merge docrails
Diffstat (limited to 'activemodel')
-rw-r--r--activemodel/README68
-rw-r--r--activemodel/lib/active_model/callbacks.rb104
-rw-r--r--activemodel/lib/active_model/conversion.rb13
-rw-r--r--activemodel/lib/active_model/dirty.rb40
-rw-r--r--activemodel/lib/active_model/validations/length.rb8
5 files changed, 180 insertions, 53 deletions
diff --git a/activemodel/README b/activemodel/README
index c20f732a12..7c9c754a8e 100644
--- a/activemodel/README
+++ b/activemodel/README
@@ -1,21 +1,57 @@
-Active Model
-==============
+= Active Model - defined interfaces for Rails
-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.
+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.
-Here's what I plan to extract:
- * ActiveModel::Observing
- * ActiveModel::Callbacks
- * ActiveModel::Validations
+Active Model is a solution for this problem.
- # for ActiveResource params and ActiveRecord options
- * ActiveModel::Scoping
+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:
- # to_json, to_xml, etc
- * ActiveModel::Serialization
+* 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.
+
+ {Learn more}[link:classes/ActiveModel/CallBacks.html]
+
+* For classes that already look like an Active Record object
+
+ class MyClass
+ include ActiveModel::Conversion
+ end
+
+ ...returns the class itself when sent :to_model
+
+* 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]
-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
diff --git a/activemodel/lib/active_model/callbacks.rb b/activemodel/lib/active_model/callbacks.rb
index f66a1ddcaa..a7e0cf90c1 100644
--- a/activemodel/lib/active_model/callbacks.rb
+++ b/activemodel/lib/active_model/callbacks.rb
@@ -1,6 +1,52 @@
require 'active_support/callbacks'
module ActiveModel
+ # == Active Model Callbacks
+ #
+ # Provides an interface for any class to have Active Record like callbacks.
+ #
+ # Like the Active Record methods, the call back chain is aborted as soon as
+ # one of the methods in the chain returns false.
+ #
+ # First, extend ActiveModel::Callbacks from the class you are creating:
+ #
+ # class MyModel
+ # extend ActiveModel::Callbacks
+ # end
+ #
+ # Then define a list of methods that you want call backs attached to:
+ #
+ # define_model_callbacks :create, :update
+ #
+ # This will provide all three standard callbacks (before, around and after) around
+ # both the :create and :update methods. To implement, you need to wrap the methods
+ # you want call backs on in a block so that the call backs get a chance to fire:
+ #
+ # def create
+ # _run_create_callbacks do
+ # # Your create action methods here
+ # end
+ # end
+ #
+ # The _run_<method_name>_callbacks methods are dynamically created when you extend
+ # the <tt>ActiveModel::Callbacks</tt> module.
+ #
+ # Then in your class, you can use the +before_create+, +after_create+ and +around_create+
+ # methods, just as you would in an Active Record module.
+ #
+ # before_create :action_before_create
+ #
+ # def action_before_create
+ # # Your code here
+ # end
+ #
+ # You can choose not to have all three callbacks by passing an hash to the
+ # define_model_callbacks method.
+ #
+ # define_model_callbacks :create, :only => :after, :before
+ #
+ # Would only create the after_create and before_create callback methods in your
+ # class.
module Callbacks
def self.extended(base)
base.class_eval do
@@ -8,43 +54,39 @@ module ActiveModel
end
end
- # Define callbacks similar to ActiveRecord ones. It means:
- #
- # * The callback chain is aborted whenever the block given to
- # _run_callbacks returns false.
- #
- # * If a class is given to the fallback, it will search for
- # before_create, around_create and after_create methods.
- #
- # == Usage
- #
- # First you need to define which callbacks your model will have:
+ # define_model_callbacks accepts all options define_callbacks does, in case you
+ # want to overwrite a default. Besides that, it also accepts an :only option,
+ # where you can choose if you want all types (before, around or after) or just some.
#
+ # define_model_callbacks :initializer, :only => :after
+ #
+ # Note, the <tt>:only => <type></tt> hash will apply to all callbacks defined on
+ # that method call. To get around this you can call the define_model_callbacks
+ # method as many times as you need.
+ #
+ # define_model_callbacks :create, :only => :after
+ # define_model_callbacks :update, :only => :before
+ # define_model_callbacks :destroy, :only => :around
+ #
+ # Would create +after_create+, +before_update+ and +around_destroy+ methods only.
+ #
+ # You can pass in a class to before_<type>, after_<type> and around_<type>, in which
+ # case the call back will call that class's <action>_<type> method passing the object
+ # that the callback is being called on.
+ #
# class MyModel
+ # extend ActiveModel::Callbacks
# define_model_callbacks :create
+ #
+ # before_create AnotherClass
# end
- #
- # This will define three class methods: before_create, around_create,
- # and after_create. They accept a symbol, a string, an object or a block.
- #
- # After you create a callback, you need to tell when they are executed.
- # For example, you could do:
- #
- # def create
- # _run_create_callbacks do
- # super
+ #
+ # class AnotherClass
+ # def self.before_create( obj )
+ # # obj is the MyModel instance that the callback is being called on
# end
# end
- #
- # == Options
- #
- # define_model_callbacks accepts all options define_callbacks does, in
- # case you want to overwrite a default. Besides that, it also accepts
- # an :only option, where you can choose if you want all types (before,
- # around or after) or just some:
- #
- # define_model_callbacks :initializer, :only => :after
- #
+ #
def define_model_callbacks(*callbacks)
options = callbacks.extract_options!
options = { :terminator => "result == false", :scope => [:kind, :name] }.merge(options)
diff --git a/activemodel/lib/active_model/conversion.rb b/activemodel/lib/active_model/conversion.rb
index d5c65920f6..c14a07c7dc 100644
--- a/activemodel/lib/active_model/conversion.rb
+++ b/activemodel/lib/active_model/conversion.rb
@@ -1,5 +1,16 @@
module ActiveModel
- # Include ActiveModel::Conversion if your object "acts like an ActiveModel model".
+ # If your object is already designed to implement all of the Active Model featurs
+ # include this module in your Class.
+ #
+ # class MyClass
+ # include ActiveModel::Conversion
+ # end
+ #
+ # Returns self to the <tt>:to_model</tt> method.
+ #
+ # If your model does not act like an Active Model object, then you should define
+ # <tt>:to_model</tt> yourself returning a proxy object that wraps your object
+ # with Active Model compliant methods.
module Conversion
def to_model
self
diff --git a/activemodel/lib/active_model/dirty.rb b/activemodel/lib/active_model/dirty.rb
index 735c61df74..5f02929a9d 100644
--- a/activemodel/lib/active_model/dirty.rb
+++ b/activemodel/lib/active_model/dirty.rb
@@ -1,5 +1,43 @@
module ActiveModel
- # Track unsaved attribute changes.
+ # <tt>ActiveModel::Dirty</tt> provides a way to track changes in your
+ # object in the same way as ActiveRecord does.
+ #
+ # The requirements to implement ActiveModel::Dirty are:
+ #
+ # * <tt>include ActiveModel::Dirty</tt> in your object
+ # * Call <tt>define_attribute_methods</tt> passing each method you want to track
+ # * Call <tt>attr_name_will_change!</tt> before each change to the tracked attribute
+ #
+ # If you wish to also track previous changes on save or update, you need to add
+ #
+ # @previously_changed = changes
+ #
+ # inside of your save or update method.
+ #
+ # A minimal implementation could be:
+ #
+ # class Person
+ #
+ # include ActiveModel::Dirty
+ #
+ # define_attribute_methods [:name]
+ #
+ # def name
+ # @name
+ # end
+ #
+ # def name=(val)
+ # name_will_change!
+ # @name = val
+ # end
+ #
+ # def save
+ # @previously_changed = changes
+ # end
+ #
+ # end
+ #
+ # == Examples:
#
# A newly instantiated object is unchanged:
# person = Person.find_by_name('Uncle Bob')
diff --git a/activemodel/lib/active_model/validations/length.rb b/activemodel/lib/active_model/validations/length.rb
index 871f589af9..9ceb75487f 100644
--- a/activemodel/lib/active_model/validations/length.rb
+++ b/activemodel/lib/active_model/validations/length.rb
@@ -57,13 +57,13 @@ module ActiveModel
#
# class Person < ActiveRecord::Base
# validates_length_of :first_name, :maximum=>30
- # validates_length_of :last_name, :maximum=>30, :message=>"less than {{count}} if you don't mind"
+ # validates_length_of :last_name, :maximum=>30, :message=>"less than 30 if you don't mind"
# validates_length_of :fax, :in => 7..32, :allow_nil => true
# validates_length_of :phone, :in => 7..32, :allow_blank => true
# validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
- # validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least {{count}} character"
- # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with {{count}} characters... don't play me."
- # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least {{count}} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
+ # validates_length_of :zip_code, :minimum => 5, :too_short => "please enter at least 5 characters"
+ # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with 4 characters... don't play me."
+ # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least 100 words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
# end
#
# Configuration options: