diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2010-01-17 03:26:20 +0530 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2010-01-17 03:26:20 +0530 |
commit | dba196cb7f8d34b93f6872e4a43737bb52019065 (patch) | |
tree | 97a2f784a2ec2bfae4f960af56a9280dad6f7774 /activemodel | |
parent | 6e3bee6cf1f0d2684152292db0a8b757249824fd (diff) | |
download | rails-dba196cb7f8d34b93f6872e4a43737bb52019065.tar.gz rails-dba196cb7f8d34b93f6872e4a43737bb52019065.tar.bz2 rails-dba196cb7f8d34b93f6872e4a43737bb52019065.zip |
Merge docrails
Diffstat (limited to 'activemodel')
-rw-r--r-- | activemodel/README | 68 | ||||
-rw-r--r-- | activemodel/lib/active_model/callbacks.rb | 104 | ||||
-rw-r--r-- | activemodel/lib/active_model/conversion.rb | 13 | ||||
-rw-r--r-- | activemodel/lib/active_model/dirty.rb | 40 | ||||
-rw-r--r-- | activemodel/lib/active_model/validations/length.rb | 8 |
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: |