activemodel 3.0.0.rc → 3.0.0.rc2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,24 +17,27 @@ module ActiveModel
17
17
  # end
18
18
  #
19
19
  # cm = ContactMessage.new
20
- # cm.to_model == self #=> true
21
- # cm.to_key #=> nil
22
- # cm.to_param #=> nil
20
+ # cm.to_model == self # => true
21
+ # cm.to_key # => nil
22
+ # cm.to_param # => nil
23
23
  #
24
24
  module Conversion
25
- # If your object is already designed to implement all of the Active Model
26
- # you can use the default to_model implementation, which simply returns
25
+ # If your object is already designed to implement all of the Active Model
26
+ # you can use the default to_model implementation, which simply returns
27
27
  # self.
28
- #
29
- # If your model does not act like an Active Model object, then you should
30
- # define <tt>:to_model</tt> yourself returning a proxy object that wraps
28
+ #
29
+ # If your model does not act like an Active Model object, then you should
30
+ # define <tt>:to_model</tt> yourself returning a proxy object that wraps
31
31
  # your object with Active Model compliant methods.
32
32
  def to_model
33
33
  self
34
34
  end
35
35
 
36
- # Returns an Enumerable of all (primary) key attributes or nil if
37
- # persisted? is false
36
+ # Returns an Enumerable of all key attributes if any is set, regardless
37
+ # if the object is persisted or not.
38
+ #
39
+ # Note the default implementation uses persisted? just because all objects
40
+ # in Ruby 1.8.x responds to :id.
38
41
  def to_key
39
42
  persisted? ? [id] : nil
40
43
  end
@@ -42,7 +45,7 @@ module ActiveModel
42
45
  # Returns a string representing the object's key suitable for use in URLs,
43
46
  # or nil if persisted? is false
44
47
  def to_param
45
- to_key ? to_key.join('-') : nil
48
+ persisted? ? to_key.join('-') : nil
46
49
  end
47
50
  end
48
51
  end
@@ -6,47 +6,48 @@ require 'active_support/core_ext/object/duplicable'
6
6
  module ActiveModel
7
7
  # == Active Model Dirty
8
8
  #
9
- # Provides a way to track changes in your object in the same way as
9
+ # Provides a way to track changes in your object in the same way as
10
10
  # Active Record does.
11
- #
11
+ #
12
12
  # The requirements to implement ActiveModel::Dirty are to:
13
13
  #
14
14
  # * <tt>include ActiveModel::Dirty</tt> in your object
15
- # * Call <tt>define_attribute_methods</tt> passing each method you want to
15
+ # * Call <tt>define_attribute_methods</tt> passing each method you want to
16
16
  # track
17
- # * Call <tt>attr_name_will_change!</tt> before each change to the tracked
17
+ # * Call <tt>attr_name_will_change!</tt> before each change to the tracked
18
18
  # attribute
19
- #
20
- # If you wish to also track previous changes on save or update, you need to
19
+ #
20
+ # If you wish to also track previous changes on save or update, you need to
21
21
  # add
22
- #
22
+ #
23
23
  # @previously_changed = changes
24
- #
24
+ #
25
25
  # inside of your save or update method.
26
- #
26
+ #
27
27
  # A minimal implementation could be:
28
- #
28
+ #
29
29
  # class Person
30
- #
30
+ #
31
31
  # include ActiveModel::Dirty
32
- #
32
+ #
33
33
  # define_attribute_methods [:name]
34
- #
34
+ #
35
35
  # def name
36
36
  # @name
37
37
  # end
38
- #
38
+ #
39
39
  # def name=(val)
40
- # name_will_change!
40
+ # name_will_change! unless val == @name
41
41
  # @name = val
42
42
  # end
43
- #
43
+ #
44
44
  # def save
45
45
  # @previously_changed = changes
46
+ # @changed_attributes.clear
46
47
  # end
47
- #
48
+ #
48
49
  # end
49
- #
50
+ #
50
51
  # == Examples:
51
52
  #
52
53
  # A newly instantiated object is unchanged:
@@ -77,13 +78,10 @@ module ActiveModel
77
78
  # person.changed # => ['name']
78
79
  # person.changes # => { 'name' => ['Bill', 'Bob'] }
79
80
  #
80
- # Resetting an attribute returns it to its original state:
81
- # person.reset_name! # => 'Bill'
82
- # person.changed? # => false
83
- # person.name_changed? # => false
84
- # person.name # => 'Bill'
81
+ # If an attribute is modified in-place then make use of <tt>[attribute_name]_will_change!</tt>
82
+ # to mark that the attribute is changing. Otherwise ActiveModel can't track changes to
83
+ # in-place attributes.
85
84
  #
86
- # Before modifying an attribute in-place:
87
85
  # person.name_will_change!
88
86
  # person.name << 'y'
89
87
  # person.name_change # => ['Bill', 'Billy']
@@ -12,50 +12,50 @@ module ActiveModel
12
12
  #
13
13
  # Provides a modified +OrderedHash+ that you can include in your object
14
14
  # for handling error messages and interacting with Action Pack helpers.
15
- #
15
+ #
16
16
  # A minimal implementation could be:
17
- #
17
+ #
18
18
  # class Person
19
- #
19
+ #
20
20
  # # Required dependency for ActiveModel::Errors
21
21
  # extend ActiveModel::Naming
22
- #
22
+ #
23
23
  # def initialize
24
24
  # @errors = ActiveModel::Errors.new(self)
25
25
  # end
26
- #
26
+ #
27
27
  # attr_accessor :name
28
28
  # attr_reader :errors
29
- #
29
+ #
30
30
  # def validate!
31
31
  # errors.add(:name, "can not be nil") if name == nil
32
32
  # end
33
- #
33
+ #
34
34
  # # The following methods are needed to be minimally implemented
35
35
  #
36
36
  # def read_attribute_for_validation(attr)
37
37
  # send(attr)
38
38
  # end
39
- #
40
- # def ErrorsPerson.human_attribute_name(attr, options = {})
39
+ #
40
+ # def Person.human_attribute_name(attr, options = {})
41
41
  # attr
42
42
  # end
43
- #
44
- # def ErrorsPerson.lookup_ancestors
43
+ #
44
+ # def Person.lookup_ancestors
45
45
  # [self]
46
46
  # end
47
- #
47
+ #
48
48
  # end
49
- #
49
+ #
50
50
  # The last three methods are required in your object for Errors to be
51
51
  # able to generate error messages correctly and also handle multiple
52
52
  # languages. Of course, if you extend your object with ActiveModel::Translations
53
53
  # you will not need to implement the last two. Likewise, using
54
54
  # ActiveModel::Validations will handle the validation related methods
55
55
  # for you.
56
- #
56
+ #
57
57
  # The above allows you to do:
58
- #
58
+ #
59
59
  # p = Person.new
60
60
  # p.validate! # => ["can not be nil"]
61
61
  # p.errors.full_messages # => ["name can not be nil"]
@@ -66,7 +66,7 @@ module ActiveModel
66
66
  CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank]
67
67
 
68
68
  # Pass in the instance of the object that is using the errors object.
69
- #
69
+ #
70
70
  # class Person
71
71
  # def initialize
72
72
  # @errors = ActiveModel::Errors.new(self)
@@ -80,23 +80,19 @@ module ActiveModel
80
80
  alias_method :get, :[]
81
81
  alias_method :set, :[]=
82
82
 
83
- # When passed a symbol or a name of a method, returns an array of errors
83
+ # When passed a symbol or a name of a method, returns an array of errors
84
84
  # for the method.
85
- #
86
- # p.errors[:name] #=> ["can not be nil"]
87
- # p.errors['name'] #=> ["can not be nil"]
85
+ #
86
+ # p.errors[:name] # => ["can not be nil"]
87
+ # p.errors['name'] # => ["can not be nil"]
88
88
  def [](attribute)
89
- if errors = get(attribute.to_sym)
90
- errors
91
- else
92
- set(attribute.to_sym, [])
93
- end
89
+ get(attribute.to_sym) || set(attribute.to_sym, [])
94
90
  end
95
91
 
96
92
  # Adds to the supplied attribute the supplied error message.
97
- #
93
+ #
98
94
  # p.errors[:name] = "must be set"
99
- # p.errors[:name] #=> ['must be set']
95
+ # p.errors[:name] # => ['must be set']
100
96
  def []=(attribute, error)
101
97
  self[attribute.to_sym] << error
102
98
  end
@@ -104,12 +100,12 @@ module ActiveModel
104
100
  # Iterates through each error key, value pair in the error messages hash.
105
101
  # Yields the attribute and the error for that attribute. If the attribute
106
102
  # has more than one error message, yields once for each error message.
107
- #
103
+ #
108
104
  # p.errors.add(:name, "can't be blank")
109
105
  # p.errors.each do |attribute, errors_array|
110
106
  # # Will yield :name and "can't be blank"
111
107
  # end
112
- #
108
+ #
113
109
  # p.errors.add(:name, "must be specified")
114
110
  # p.errors.each do |attribute, errors_array|
115
111
  # # Will yield :name and "can't be blank"
@@ -122,29 +118,29 @@ module ActiveModel
122
118
  end
123
119
 
124
120
  # Returns the number of error messages.
125
- #
121
+ #
126
122
  # p.errors.add(:name, "can't be blank")
127
- # p.errors.size #=> 1
123
+ # p.errors.size # => 1
128
124
  # p.errors.add(:name, "must be specified")
129
- # p.errors.size #=> 2
125
+ # p.errors.size # => 2
130
126
  def size
131
127
  values.flatten.size
132
128
  end
133
129
 
134
130
  # Returns an array of error messages, with the attribute name included
135
- #
131
+ #
136
132
  # p.errors.add(:name, "can't be blank")
137
133
  # p.errors.add(:name, "must be specified")
138
- # p.errors.to_a #=> ["name can't be blank", "name must be specified"]
134
+ # p.errors.to_a # => ["name can't be blank", "name must be specified"]
139
135
  def to_a
140
136
  full_messages
141
137
  end
142
138
 
143
139
  # Returns the number of error messages.
144
140
  # p.errors.add(:name, "can't be blank")
145
- # p.errors.count #=> 1
141
+ # p.errors.count # => 1
146
142
  # p.errors.add(:name, "must be specified")
147
- # p.errors.count #=> 2
143
+ # p.errors.count # => 2
148
144
  def count
149
145
  to_a.size
150
146
  end
@@ -155,11 +151,11 @@ module ActiveModel
155
151
  end
156
152
 
157
153
  # Returns an xml formatted representation of the Errors hash.
158
- #
154
+ #
159
155
  # p.errors.add(:name, "can't be blank")
160
156
  # p.errors.add(:name, "must be specified")
161
- # p.errors.to_xml #=> Produces:
162
- #
157
+ # p.errors.to_xml
158
+ # # =>
163
159
  # # <?xml version=\"1.0\" encoding=\"UTF-8\"?>
164
160
  # # <errors>
165
161
  # # <error>name can't be blank</error>
@@ -169,16 +165,16 @@ module ActiveModel
169
165
  to_a.to_xml options.reverse_merge(:root => "errors", :skip_types => true)
170
166
  end
171
167
 
172
- # Returns an array as JSON representation for this object.
168
+ # Returns an ActiveSupport::OrderedHash that can be used as the JSON representation for this object.
173
169
  def as_json(options=nil)
174
- to_a
170
+ self
175
171
  end
176
172
 
177
173
  # Adds +message+ to the error messages on +attribute+, which will be returned on a call to
178
174
  # <tt>on(attribute)</tt> for the same attribute. More than one error can be added to the same
179
175
  # +attribute+ in which case an array will be returned on a call to <tt>on(attribute)</tt>.
180
176
  # If no +message+ is supplied, <tt>:invalid</tt> is assumed.
181
- #
177
+ #
182
178
  # If +message+ is a symbol, it will be translated using the appropriate scope (see +translate_error+).
183
179
  # If +message+ is a proc, it will be called, allowing for things like <tt>Time.now</tt> to be used within an error.
184
180
  def add(attribute, message = nil, options = {})
@@ -257,19 +253,19 @@ module ActiveModel
257
253
  full_messages
258
254
  end
259
255
 
260
- # Translates an error message in its default scope
256
+ # Translates an error message in its default scope
261
257
  # (<tt>activemodel.errors.messages</tt>).
262
258
  #
263
- # Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
264
- # if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not
265
- # there also, it returns the translation of the default message
259
+ # Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
260
+ # if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if that is not
261
+ # there also, it returns the translation of the default message
266
262
  # (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model name,
267
263
  # translated attribute name and the value are available for interpolation.
268
264
  #
269
265
  # When using inheritance in your models, it will check all the inherited
270
266
  # models too, but only if the model itself hasn't been found. Say you have
271
- # <tt>class Admin < User; end</tt> and you wanted the translation for
272
- # the <tt>:blank</tt> error +message+ for the <tt>title</tt> +attribute+,
267
+ # <tt>class Admin < User; end</tt> and you wanted the translation for
268
+ # the <tt>:blank</tt> error +message+ for the <tt>title</tt> +attribute+,
273
269
  # it looks for these translations:
274
270
  #
275
271
  # <ol>
@@ -38,6 +38,7 @@ module ActiveModel
38
38
  # not persisted?, then to_param should always return nil.
39
39
  def test_to_param
40
40
  assert model.respond_to?(:to_param), "The model should respond to to_param"
41
+ def model.to_key() [1] end
41
42
  def model.persisted?() false end
42
43
  assert model.to_param.nil?
43
44
  end
@@ -79,7 +80,7 @@ module ActiveModel
79
80
  end
80
81
 
81
82
  # == Errors Testing
82
- #
83
+ #
83
84
  # Returns an object that has :[] and :full_messages defined on it. See below
84
85
  # for more details.
85
86
  #
@@ -17,7 +17,10 @@ module ActiveModel
17
17
  end
18
18
 
19
19
  # Transform the model name into a more humane format, using I18n. By default,
20
- # it will underscore then humanize the class name (BlogPost.model_name.human #=> "Blog post").
20
+ # it will underscore then humanize the class name
21
+ #
22
+ # BlogPost.model_name.human # => "Blog post"
23
+ #
21
24
  # Specify +options+ with additional translating options.
22
25
  def human(options={})
23
26
  return @human unless @klass.respond_to?(:lookup_ancestors) &&
@@ -38,16 +41,16 @@ module ActiveModel
38
41
  # == Active Model Naming
39
42
  #
40
43
  # Creates a +model_name+ method on your object.
41
- #
44
+ #
42
45
  # To implement, just extend ActiveModel::Naming in your object:
43
- #
46
+ #
44
47
  # class BookCover
45
48
  # extend ActiveModel::Naming
46
49
  # end
47
- #
48
- # BookCover.model_name #=> "BookCover"
49
- # BookCover.model_name.human #=> "Book cover"
50
- #
50
+ #
51
+ # BookCover.model_name # => "BookCover"
52
+ # BookCover.model_name.human # => "Book cover"
53
+ #
51
54
  # Providing the functionality that ActiveModel::Naming provides in your object
52
55
  # is required to pass the Active Model Lint test. So either extending the provided
53
56
  # method below, or rolling your own is required..
@@ -87,5 +90,5 @@ module ActiveModel
87
90
  (record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
88
91
  end
89
92
  end
90
-
93
+
91
94
  end
@@ -10,7 +10,7 @@ module ActiveModel
10
10
 
11
11
  module ClassMethods
12
12
  # == Active Model Observers Activation
13
- #
13
+ #
14
14
  # Activates the observers assigned. Examples:
15
15
  #
16
16
  # # Calls PersonObserver.instance
@@ -22,7 +22,7 @@ module ActiveModel
22
22
  # # Same as above, just using explicit class references
23
23
  # ActiveRecord::Base.observers = Cacher, GarbageCollector
24
24
  #
25
- # Note: Setting this does not instantiate the observers yet.
25
+ # Note: Setting this does not instantiate the observers yet.
26
26
  # +instantiate_observers+ is called during startup, and before
27
27
  # each development request.
28
28
  def observers=(*values)
@@ -123,9 +123,9 @@ module ActiveModel
123
123
  #
124
124
  # Observers will by default be mapped to the class with which they share a
125
125
  # name. So CommentObserver will be tied to observing Comment, ProductManagerObserver
126
- # to ProductManager, and so on. If you want to name your observer differently than
127
- # the class you're interested in observing, you can use the Observer.observe class
128
- # method which takes either the concrete class (Product) or a symbol for that
126
+ # to ProductManager, and so on. If you want to name your observer differently than
127
+ # the class you're interested in observing, you can use the Observer.observe class
128
+ # method which takes either the concrete class (Product) or a symbol for that
129
129
  # class (:product):
130
130
  #
131
131
  # class AuditObserver < ActiveModel::Observer
@@ -136,7 +136,7 @@ module ActiveModel
136
136
  # end
137
137
  # end
138
138
  #
139
- # If the audit observer needs to watch more than one kind of object, this can be
139
+ # If the audit observer needs to watch more than one kind of object, this can be
140
140
  # specified with multiple arguments:
141
141
  #
142
142
  # class AuditObserver < ActiveModel::Observer
@@ -147,7 +147,7 @@ module ActiveModel
147
147
  # end
148
148
  # end
149
149
  #
150
- # The AuditObserver will now act on both updates to Account and Balance by treating
150
+ # The AuditObserver will now act on both updates to Account and Balance by treating
151
151
  # them both as records.
152
152
  #
153
153
  class Observer