activemodel 3.0.0.rc → 3.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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