activemodel 4.1.16 → 4.2.0.beta1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activemodel might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 661ea74dd96dd480e27c5b1e091706dcdd79f6ae
4
- data.tar.gz: 37bec8de391a4ebb5471e9e0e790f47227cae388
3
+ metadata.gz: c0ba324f942bc460e8ac9ddf05db07b267fddba7
4
+ data.tar.gz: dcc2d9b2e52755dc827b2880015524238d1d7b69
5
5
  SHA512:
6
- metadata.gz: 5af0edd2875a47bcb27e33c045c998dda2127d524833f884f3fa93132ae5b6a2757c070efc1d6d78ce13c666b2dd508fae86f1e3600dbbed812ad7ad86a793bb
7
- data.tar.gz: fe161cb9636658586d2ce6eb7d822c15865f954dd34ac2d3cc9b9f80ab8883b1f6de0f00f24b8012f0524585c15d4c790a0e6744fc070bb094dc0d5e55f73a99
6
+ metadata.gz: e3c419a3cbe8624a7a38c212c8cb87e6931cc0b8319090c0fbe7029cc4650f875d4faba74dbe009d8940e6fd7a7fd8e3bb4d4d8c2059fb91663609f08f684931
7
+ data.tar.gz: 2fb78243d20a5ba5d167b132946d782629ea932308ff1ba970bf177ee0e79894b62b13985a112abd43a0cf3357071510090a6bbea38d3ce82eb2b0774fbec4ed
@@ -1,169 +1,58 @@
1
- ## Rails 4.1.16 (July 12, 2016) ##
1
+ * Passwords with spaces only allowed in `ActiveModel::SecurePassword`.
2
2
 
3
- * No changes.
3
+ Presence validation can be used to restore old behavior.
4
4
 
5
+ *Yevhene Shemet*
5
6
 
6
- ## Rails 4.1.15 (March 07, 2016) ##
7
+ * Validate options passed to `ActiveModel::Validations.validate`.
7
8
 
8
- * No changes.
9
+ Preventing, in many cases, the simple mistake of using `validate` instead of `validates`.
9
10
 
11
+ *Sonny Michaud*
10
12
 
11
- ## Rails 4.1.14.2 (February 26, 2016) ##
13
+ * Deprecate `reset_#{attribute}` in favor of `restore_#{attribute}`.
12
14
 
13
- * No changes.
15
+ These methods may cause confusion with the `reset_changes` that behaves differently
16
+ of them.
14
17
 
18
+ * Deprecate `ActiveModel::Dirty#reset_changes` in favor of `#clear_changes_information`.
15
19
 
16
- ## Rails 4.1.14.1 (January 25, 2015) ##
20
+ This method name is causing confusion with the `reset_#{attribute}`
21
+ methods. While `reset_name` set the value of the name attribute for the
22
+ previous value `reset_changes` only discard the changes and previous
23
+ changes.
17
24
 
18
- * No changes.
25
+ * Added `restore_attributes` method to `ActiveModel::Dirty` API to restore all the
26
+ changed values to the previous data.
19
27
 
28
+ *Igor G.*
20
29
 
21
- ## Rails 4.1.14 (November 12, 2015) ##
30
+ * Allow proc and symbol as values for `only_integer` of `NumericalityValidator`
22
31
 
23
- * No changes.
32
+ *Robin Mehner*
24
33
 
34
+ * `has_secure_password` now verifies that the given password is less than 72
35
+ characters if validations are enabled.
25
36
 
26
- ## Rails 4.1.13 (August 24, 2015) ##
37
+ Fixes #14591.
27
38
 
28
- * No changes.
39
+ *Akshay Vishnoi*
29
40
 
41
+ * Remove deprecated `Validator#setup` without replacement.
30
42
 
31
- ## Rails 4.1.12 (June 25, 2015) ##
43
+ See #10716.
32
44
 
33
- * No changes.
45
+ *Kuldeep Aggarwal*
34
46
 
47
+ * Add plural and singular form for length validator's default messages.
35
48
 
36
- ## Rails 4.1.11 (June 16, 2015) ##
49
+ *Abd ar-Rahman Hamid*
37
50
 
38
- * No changes.
51
+ * Introduce `validate` as an alias for `valid?`.
39
52
 
53
+ This is more intuitive when you want to run validations but don't care about
54
+ the return value.
40
55
 
41
- ## Rails 4.1.10 (March 19, 2015) ##
56
+ *Henrik Nyh*
42
57
 
43
- * No changes.
44
-
45
-
46
- ## Rails 4.1.9 (January 6, 2015) ##
47
-
48
- * No changes.
49
-
50
-
51
- ## Rails 4.1.8 (November 16, 2014) ##
52
-
53
- * No changes.
54
-
55
-
56
- ## Rails 4.1.7.1 (November 19, 2014) ##
57
-
58
- * No changes.
59
-
60
-
61
- ## Rails 4.1.7 (October 29, 2014) ##
62
-
63
- * No changes.
64
-
65
-
66
- ## Rails 4.1.6 (September 11, 2014) ##
67
-
68
- * No changes.
69
-
70
-
71
- ## Rails 4.1.5 (August 18, 2014) ##
72
-
73
- * No changes.
74
-
75
-
76
- ## Rails 4.1.4 (July 2, 2014) ##
77
-
78
- * No changes.
79
-
80
-
81
- ## Rails 4.1.3 (July 2, 2014) ##
82
-
83
- * No changes.
84
-
85
-
86
- ## Rails 4.1.2 (June 26, 2014) ##
87
-
88
- * No changes.
89
-
90
-
91
- ## Rails 4.1.1 (May 6, 2014) ##
92
-
93
- * No changes.
94
-
95
-
96
- ## Rails 4.1.0 (April 8, 2014) ##
97
-
98
- * `#to_param` returns `nil` if `#to_key` returns `nil`. Fixes #11399.
99
-
100
- *Yves Senn*
101
-
102
- * Ability to specify multiple contexts when defining a validation.
103
-
104
- Example:
105
-
106
- class Person
107
- include ActiveModel::Validations
108
-
109
- attr_reader :name
110
- validates_presence_of :name, on: [:verify, :approve]
111
- end
112
-
113
- person = Person.new
114
- person.valid? # => true
115
- person.valid?(:verify) # => false
116
- person.errors.full_messages_for(:name) # => ["Name can't be blank"]
117
- person.valid?(:approve) # => false
118
- person.errors.full_messages_for(:name) # => ["Name can't be blank"]
119
-
120
- *Vince Puzzella*
121
-
122
- * `attribute_changed?` now accepts a hash to check if the attribute was
123
- changed `:from` and/or `:to` a given value.
124
-
125
- Example:
126
-
127
- model.name_changed?(from: "Pete", to: "Ringo")
128
-
129
- *Tejas Dinkar*
130
-
131
- * Fix `has_secure_password` to honor bcrypt-ruby's cost attribute.
132
-
133
- *T.J. Schuck*
134
-
135
- * Updated the `ActiveModel::Dirty#changed_attributes` method to be indifferent between using
136
- symbols and strings as keys.
137
-
138
- *William Myers*
139
-
140
- * Added new API methods `reset_changes` and `changes_applied` to `ActiveModel::Dirty`
141
- that control changes state. Previsously you needed to update internal
142
- instance variables, but now API methods are available.
143
-
144
- *Bogdan Gusiev*
145
-
146
- * Fix `has_secure_password` not to trigger `password_confirmation` validations
147
- if no `password_confirmation` is set.
148
-
149
- *Vladimir Kiselev*
150
-
151
- * `inclusion` / `exclusion` validations with ranges will only use the faster
152
- `Range#cover` for numerical ranges, and the more accurate `Range#include?`
153
- for non-numerical ones.
154
-
155
- Fixes range validations like `:a..:f` that used to pass with values like `:be`.
156
- Fixes #10593.
157
-
158
- *Charles Bergeron*
159
-
160
- * Fix regression in `has_secure_password`. When a password is set, but a
161
- confirmation is an empty string, it would incorrectly save.
162
-
163
- *Steve Klabnik* and *Phillip Calvin*
164
-
165
- * Deprecate `Validator#setup`. This should be done manually now in the validator's constructor.
166
-
167
- *Nick Sutterer*
168
-
169
- Please check [4-0-stable](https://github.com/rails/rails/blob/4-0-stable/activemodel/CHANGELOG.md) for previous changes.
58
+ Please check [4-1-stable](https://github.com/rails/rails/blob/4-1-stable/activemodel/CHANGELOG.md) for previous changes.
@@ -49,7 +49,8 @@ behavior out of the box:
49
49
  send("#{attr}=", nil)
50
50
  end
51
51
  end
52
-
52
+
53
+ person = Person.new
53
54
  person.clear_name
54
55
  person.clear_age
55
56
 
@@ -78,7 +79,21 @@ behavior out of the box:
78
79
  class Person
79
80
  include ActiveModel::Dirty
80
81
 
81
- attr_accessor :name
82
+ define_attribute_methods :name
83
+
84
+ def name
85
+ @name
86
+ end
87
+
88
+ def name=(val)
89
+ name_will_change! unless val == @name
90
+ @name = val
91
+ end
92
+
93
+ def save
94
+ # do persistence work
95
+ changes_applied
96
+ end
82
97
  end
83
98
 
84
99
  person = Person.new
@@ -88,6 +103,7 @@ behavior out of the box:
88
103
  person.changed? # => true
89
104
  person.changed # => ['name']
90
105
  person.changes # => { 'name' => [nil, 'bob'] }
106
+ person.save
91
107
  person.name = 'robert'
92
108
  person.save
93
109
  person.previous_changes # => {'name' => ['bob, 'robert']}
@@ -116,7 +132,10 @@ behavior out of the box:
116
132
  "Name"
117
133
  end
118
134
  end
119
-
135
+
136
+ person = Person.new
137
+ person.name = nil
138
+ person.validate!
120
139
  person.errors.full_messages
121
140
  # => ["Name cannot be nil"]
122
141
 
@@ -128,7 +147,7 @@ behavior out of the box:
128
147
  extend ActiveModel::Naming
129
148
  end
130
149
 
131
- NamedPerson.model_name # => "NamedPerson"
150
+ NamedPerson.model_name.name # => "NamedPerson"
132
151
  NamedPerson.model_name.human # => "Named person"
133
152
 
134
153
  {Learn more}[link:classes/ActiveModel/Naming.html]
@@ -180,41 +199,41 @@ behavior out of the box:
180
199
 
181
200
  * Validation support
182
201
 
183
- class Person
184
- include ActiveModel::Validations
202
+ class Person
203
+ include ActiveModel::Validations
185
204
 
186
- attr_accessor :first_name, :last_name
205
+ attr_accessor :first_name, :last_name
187
206
 
188
- validates_each :first_name, :last_name do |record, attr, value|
189
- record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
190
- end
191
- end
207
+ validates_each :first_name, :last_name do |record, attr, value|
208
+ record.errors.add attr, 'starts with z.' if value.to_s[0] == ?z
209
+ end
210
+ end
192
211
 
193
- person = Person.new
194
- person.first_name = 'zoolander'
195
- person.valid? # => false
212
+ person = Person.new
213
+ person.first_name = 'zoolander'
214
+ person.valid? # => false
196
215
 
197
216
  {Learn more}[link:classes/ActiveModel/Validations.html]
198
217
 
199
218
  * Custom validators
219
+
220
+ class HasNameValidator < ActiveModel::Validator
221
+ def validate(record)
222
+ record.errors[:name] = "must exist" if record.name.blank?
223
+ end
224
+ end
200
225
 
201
- class ValidatorPerson
202
- include ActiveModel::Validations
203
- validates_with HasNameValidator
204
- attr_accessor :name
205
- end
206
-
207
- class HasNameValidator < ActiveModel::Validator
208
- def validate(record)
209
- record.errors[:name] = "must exist" if record.name.blank?
210
- end
211
- end
226
+ class ValidatorPerson
227
+ include ActiveModel::Validations
228
+ validates_with HasNameValidator
229
+ attr_accessor :name
230
+ end
212
231
 
213
- p = ValidatorPerson.new
214
- p.valid? # => false
215
- p.errors.full_messages # => ["Name must exist"]
216
- p.name = "Bob"
217
- p.valid? # => true
232
+ p = ValidatorPerson.new
233
+ p.valid? # => false
234
+ p.errors.full_messages # => ["Name must exist"]
235
+ p.name = "Bob"
236
+ p.valid? # => true
218
237
 
219
238
  {Learn more}[link:classes/ActiveModel/Validator.html]
220
239
 
@@ -227,7 +246,7 @@ The latest version of Active Model can be installed with RubyGems:
227
246
 
228
247
  Source code can be downloaded as part of the Rails project on GitHub
229
248
 
230
- * https://github.com/rails/rails/tree/4-1-stable/activemodel
249
+ * https://github.com/rails/rails/tree/master/activemodel
231
250
 
232
251
 
233
252
  == License
@@ -243,6 +262,11 @@ API documentation is at
243
262
 
244
263
  * http://api.rubyonrails.org
245
264
 
246
- Bug reports and feature requests can be filed with the rest for the Ruby on Rails project here:
265
+ Bug reports can be filed for the Ruby on Rails project here:
247
266
 
248
267
  * https://github.com/rails/rails/issues
268
+
269
+ Feature requests should be discussed on the rails-core mailing list here:
270
+
271
+ * https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
272
+
@@ -40,13 +40,15 @@ module ActiveModel
40
40
  self
41
41
  end
42
42
 
43
- # Returns an Enumerable of all key attributes if any is set, regardless if
43
+ # Returns an Array of all key attributes if any is set, regardless if
44
44
  # the object is persisted or not. Returns +nil+ if there are no key attributes.
45
45
  #
46
- # class Person < ActiveRecord::Base
46
+ # class Person
47
+ # include ActiveModel::Conversion
48
+ # attr_accessor :id
47
49
  # end
48
50
  #
49
- # person = Person.create
51
+ # person = Person.create(id: 1)
50
52
  # person.to_key # => [1]
51
53
  def to_key
52
54
  key = respond_to?(:id) && id
@@ -56,10 +58,15 @@ module ActiveModel
56
58
  # Returns a +string+ representing the object's key suitable for use in URLs,
57
59
  # or +nil+ if <tt>persisted?</tt> is +false+.
58
60
  #
59
- # class Person < ActiveRecord::Base
61
+ # class Person
62
+ # include ActiveModel::Conversion
63
+ # attr_accessor :id
64
+ # def persisted?
65
+ # true
66
+ # end
60
67
  # end
61
68
  #
62
- # person = Person.create
69
+ # person = Person.create(id: 1)
63
70
  # person.to_param # => "1"
64
71
  def to_param
65
72
  (persisted? && key = to_key) ? key.join('-') : nil
@@ -83,8 +90,8 @@ module ActiveModel
83
90
  # internal method and should not be accessed directly.
84
91
  def _to_partial_path #:nodoc:
85
92
  @_to_partial_path ||= begin
86
- element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self))
87
- collection = ActiveSupport::Inflector.tableize(self)
93
+ element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name))
94
+ collection = ActiveSupport::Inflector.tableize(name)
88
95
  "#{collection}/#{element}".freeze
89
96
  end
90
97
  end
@@ -15,8 +15,9 @@ module ActiveModel
15
15
  # * Call <tt>attr_name_will_change!</tt> before each change to the tracked
16
16
  # attribute.
17
17
  # * Call <tt>changes_applied</tt> after the changes are persisted.
18
- # * Call <tt>reset_changes</tt> when you want to reset the changes
18
+ # * Call <tt>clear_changes_information</tt> when you want to reset the changes
19
19
  # information.
20
+ # * Call <tt>restore_attributes</tt> when you want to restore previous data.
20
21
  #
21
22
  # A minimal implementation could be:
22
23
  #
@@ -36,11 +37,18 @@ module ActiveModel
36
37
  #
37
38
  # def save
38
39
  # # do persistence work
40
+ #
39
41
  # changes_applied
40
42
  # end
41
43
  #
42
44
  # def reload!
43
- # reset_changes
45
+ # # get the values from the persistence layer
46
+ #
47
+ # clear_changes_information
48
+ # end
49
+ #
50
+ # def rollback!
51
+ # restore_attributes
44
52
  # end
45
53
  # end
46
54
  #
@@ -72,6 +80,13 @@ module ActiveModel
72
80
  # person.reload!
73
81
  # person.previous_changes # => {}
74
82
  #
83
+ # Rollback the changes:
84
+ #
85
+ # person.name = "Uncle Bob"
86
+ # person.rollback!
87
+ # person.name # => "Bill"
88
+ # person.name_changed? # => false
89
+ #
75
90
  # Assigning the same value leaves the attribute unchanged:
76
91
  #
77
92
  # person.name = 'Bill'
@@ -84,9 +99,11 @@ module ActiveModel
84
99
  # person.changed # => ["name"]
85
100
  # person.changes # => {"name" => ["Bill", "Bob"]}
86
101
  #
87
- # If an attribute is modified in-place then make use of <tt>[attribute_name]_will_change!</tt>
88
- # to mark that the attribute is changing. Otherwise ActiveModel can't track
89
- # changes to in-place attributes.
102
+ # If an attribute is modified in-place then make use of
103
+ # +[attribute_name]_will_change!+ to mark that the attribute is changing.
104
+ # Otherwise Active Model can't track changes to in-place attributes. Note
105
+ # that Active Record can detect in-place modifications automatically. You do
106
+ # not need to call +[attribute_name]_will_change!+ on Active Record models.
90
107
  #
91
108
  # person.name_will_change!
92
109
  # person.name_change # => ["Bill", "Bill"]
@@ -99,6 +116,7 @@ module ActiveModel
99
116
  included do
100
117
  attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
101
118
  attribute_method_affix prefix: 'reset_', suffix: '!'
119
+ attribute_method_affix prefix: 'restore_', suffix: '!'
102
120
  end
103
121
 
104
122
  # Returns +true+ if any attribute have unsaved changes, +false+ otherwise.
@@ -162,20 +180,30 @@ module ActiveModel
162
180
  attribute_changed?(attr) ? changed_attributes[attr] : __send__(attr)
163
181
  end
164
182
 
183
+ # Restore all previous data of the provided attributes.
184
+ def restore_attributes(attributes = changed)
185
+ attributes.each { |attr| restore_attribute! attr }
186
+ end
187
+
165
188
  private
166
189
 
167
190
  # Removes current changes and makes them accessible through +previous_changes+.
168
- def changes_applied
191
+ def changes_applied # :doc:
169
192
  @previously_changed = changes
170
193
  @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
171
194
  end
172
195
 
173
- # Removes all dirty data: current changes and previous changes
174
- def reset_changes
196
+ # Clear all dirty data: current changes and previous changes.
197
+ def clear_changes_information # :doc:
175
198
  @previously_changed = ActiveSupport::HashWithIndifferentAccess.new
176
199
  @changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
177
200
  end
178
201
 
202
+ def reset_changes
203
+ ActiveSupport::Deprecation.warn "#reset_changes is deprecated and will be removed on Rails 5. Please use #clear_changes_information instead."
204
+ clear_changes_information
205
+ end
206
+
179
207
  # Handle <tt>*_change</tt> for +method_missing+.
180
208
  def attribute_change(attr)
181
209
  [changed_attributes[attr], __send__(attr)] if attribute_changed?(attr)
@@ -191,15 +219,36 @@ module ActiveModel
191
219
  rescue TypeError, NoMethodError
192
220
  end
193
221
 
194
- changed_attributes[attr] = value
222
+ set_attribute_was(attr, value)
195
223
  end
196
224
 
197
225
  # Handle <tt>reset_*!</tt> for +method_missing+.
198
226
  def reset_attribute!(attr)
227
+ ActiveSupport::Deprecation.warn "#reset_#{attr}! is deprecated and will be removed on Rails 5. Please use #restore_#{attr}! instead."
228
+
229
+ restore_attribute!(attr)
230
+ end
231
+
232
+ # Handle <tt>restore_*!</tt> for +method_missing+.
233
+ def restore_attribute!(attr)
199
234
  if attribute_changed?(attr)
200
235
  __send__("#{attr}=", changed_attributes[attr])
201
- changed_attributes.delete(attr)
236
+ clear_attribute_changes([attr])
202
237
  end
203
238
  end
239
+
240
+ # This is necessary because `changed_attributes` might be overridden in
241
+ # other implemntations (e.g. in `ActiveRecord`)
242
+ alias_method :attributes_changed_by_setter, :changed_attributes # :nodoc:
243
+
244
+ # Force an attribute to have a particular "before" value
245
+ def set_attribute_was(attr, old_value)
246
+ attributes_changed_by_setter[attr] = old_value
247
+ end
248
+
249
+ # Remove changes information for the provided attributes.
250
+ def clear_attribute_changes(attributes)
251
+ attributes_changed_by_setter.except!(*attributes)
252
+ end
204
253
  end
205
254
  end
@@ -23,7 +23,7 @@ module ActiveModel
23
23
  # attr_reader :errors
24
24
  #
25
25
  # def validate!
26
- # errors.add(:name, "cannot be nil") if name == nil
26
+ # errors.add(:name, "cannot be nil") if name.nil?
27
27
  # end
28
28
  #
29
29
  # # The following methods are needed to be minimally implemented
@@ -289,6 +289,13 @@ module ActiveModel
289
289
  # # => NameIsInvalid: name is invalid
290
290
  #
291
291
  # person.errors.messages # => {}
292
+ #
293
+ # +attribute+ should be set to <tt>:base</tt> if the error is not
294
+ # directly associated with a single attribute.
295
+ #
296
+ # person.errors.add(:base, "either name or email must be present")
297
+ # person.errors.messages
298
+ # # => {:base=>["either name or email must be present"]}
292
299
  def add(attribute, message = :invalid, options = {})
293
300
  message = normalize_message(attribute, message, options)
294
301
  if exception = options[:strict]
@@ -427,7 +434,7 @@ module ActiveModel
427
434
 
428
435
  options = {
429
436
  default: defaults,
430
- model: @base.class.model_name.human,
437
+ model: @base.model_name.human,
431
438
  attribute: @base.class.human_attribute_name(attribute),
432
439
  value: value
433
440
  }.merge!(options)
@@ -6,9 +6,9 @@ module ActiveModel
6
6
 
7
7
  module VERSION
8
8
  MAJOR = 4
9
- MINOR = 1
10
- TINY = 16
11
- PRE = nil
9
+ MINOR = 2
10
+ TINY = 0
11
+ PRE = "beta1"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -73,16 +73,19 @@ module ActiveModel
73
73
 
74
74
  # == \Naming
75
75
  #
76
- # Model.model_name must return a string with some convenience methods:
77
- # <tt>:human</tt>, <tt>:singular</tt> and <tt>:plural</tt>. Check
78
- # ActiveModel::Naming for more information.
76
+ # Model.model_name and Model#model_name must return a string with some
77
+ # convenience methods: # <tt>:human</tt>, <tt>:singular</tt> and
78
+ # <tt>:plural</tt>. Check ActiveModel::Naming for more information.
79
79
  def test_model_naming
80
- assert model.class.respond_to?(:model_name), "The model should respond to model_name"
80
+ assert model.class.respond_to?(:model_name), "The model class should respond to model_name"
81
81
  model_name = model.class.model_name
82
82
  assert model_name.respond_to?(:to_str)
83
83
  assert model_name.human.respond_to?(:to_str)
84
84
  assert model_name.singular.respond_to?(:to_str)
85
85
  assert model_name.plural.respond_to?(:to_str)
86
+
87
+ assert model.respond_to?(:model_name), "The model instance should respond to model_name"
88
+ assert_equal model.model_name, model.class.model_name
86
89
  end
87
90
 
88
91
  # == \Errors Testing
@@ -14,9 +14,15 @@ en:
14
14
  empty: "can't be empty"
15
15
  blank: "can't be blank"
16
16
  present: "must be blank"
17
- too_long: "is too long (maximum is %{count} characters)"
18
- too_short: "is too short (minimum is %{count} characters)"
19
- wrong_length: "is the wrong length (should be %{count} characters)"
17
+ too_long:
18
+ one: "is too long (maximum is 1 character)"
19
+ other: "is too long (maximum is %{count} characters)"
20
+ too_short:
21
+ one: "is too short (minimum is 1 character)"
22
+ other: "is too short (minimum is %{count} characters)"
23
+ wrong_length:
24
+ one: "is the wrong length (should be 1 character)"
25
+ other: "is the wrong length (should be %{count} characters)"
20
26
  not_a_number: "is not a number"
21
27
  not_an_integer: "must be an integer"
22
28
  greater_than: "must be greater than %{count}"
@@ -16,8 +16,8 @@ module ActiveModel
16
16
  # end
17
17
  #
18
18
  # person = Person.new(name: 'bob', age: '18')
19
- # person.name # => 'bob'
20
- # person.age # => 18
19
+ # person.name # => "bob"
20
+ # person.age # => "18"
21
21
  #
22
22
  # Note that, by default, <tt>ActiveModel::Model</tt> implements <tt>persisted?</tt>
23
23
  # to return +false+, which is the most common case. You may want to override
@@ -74,7 +74,7 @@ module ActiveModel
74
74
  #
75
75
  # person = Person.new(name: 'bob', age: '18')
76
76
  # person.name # => "bob"
77
- # person.age # => 18
77
+ # person.age # => "18"
78
78
  def initialize(params={})
79
79
  params.each do |attr, value|
80
80
  self.public_send("#{attr}=", value)
@@ -129,7 +129,7 @@ module ActiveModel
129
129
  #
130
130
  # Equivalent to +to_s+.
131
131
  delegate :==, :===, :<=>, :=~, :"!~", :eql?, :to_s,
132
- :to_str, :as_json, to: :name
132
+ :to_str, to: :name
133
133
 
134
134
  # Returns a new ActiveModel::Name instance. By default, the +namespace+
135
135
  # and +name+ option will take the namespace and name of the given class
@@ -204,7 +204,7 @@ module ActiveModel
204
204
  # extend ActiveModel::Naming
205
205
  # end
206
206
  #
207
- # BookCover.model_name # => "BookCover"
207
+ # BookCover.model_name.name # => "BookCover"
208
208
  # BookCover.model_name.human # => "Book cover"
209
209
  #
210
210
  # BookCover.model_name.i18n_key # => :book_cover
@@ -214,14 +214,20 @@ module ActiveModel
214
214
  # is required to pass the Active Model Lint test. So either extending the
215
215
  # provided method below, or rolling your own is required.
216
216
  module Naming
217
+ def self.extended(base) #:nodoc:
218
+ base.remove_possible_method :model_name
219
+ base.delegate :model_name, to: :class
220
+ end
221
+
217
222
  # Returns an ActiveModel::Name object for module. It can be
218
223
  # used to retrieve all kinds of naming-related information
219
224
  # (See ActiveModel::Name for more information).
220
225
  #
221
- # class Person < ActiveModel::Model
226
+ # class Person
227
+ # include ActiveModel::Model
222
228
  # end
223
229
  #
224
- # Person.model_name # => Person
230
+ # Person.model_name.name # => "Person"
225
231
  # Person.model_name.class # => ActiveModel::Name
226
232
  # Person.model_name.singular # => "person"
227
233
  # Person.model_name.plural # => "people"
@@ -298,12 +304,10 @@ module ActiveModel
298
304
  end
299
305
 
300
306
  def self.model_name_from_record_or_class(record_or_class) #:nodoc:
301
- if record_or_class.respond_to?(:model_name)
302
- record_or_class.model_name
303
- elsif record_or_class.respond_to?(:to_model)
304
- record_or_class.to_model.class.model_name
307
+ if record_or_class.respond_to?(:to_model)
308
+ record_or_class.to_model.model_name
305
309
  else
306
- record_or_class.class.model_name
310
+ record_or_class.model_name
307
311
  end
308
312
  end
309
313
  private_class_method :model_name_from_record_or_class
@@ -2,6 +2,11 @@ module ActiveModel
2
2
  module SecurePassword
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ # BCrypt hash function can handle maximum 72 characters, and if we pass
6
+ # password of length more than 72 characters it ignores extra characters.
7
+ # Hence need to put a restriction on password length.
8
+ MAX_PASSWORD_LENGTH_ALLOWED = 72
9
+
5
10
  class << self
6
11
  attr_accessor :min_cost # :nodoc:
7
12
  end
@@ -11,16 +16,20 @@ module ActiveModel
11
16
  # Adds methods to set and authenticate against a BCrypt password.
12
17
  # This mechanism requires you to have a +password_digest+ attribute.
13
18
  #
14
- # Validations for presence of password on create, confirmation of password
15
- # (using a +password_confirmation+ attribute) are automatically added. If
16
- # you wish to turn off validations, pass <tt>validations: false</tt> as an
17
- # argument. You can add more validations by hand if need be.
19
+ # The following validations are added automatically:
20
+ # * Password must be present on creation
21
+ # * Password length should be less than or equal to 72 characters
22
+ # * Confirmation of password (using a +password_confirmation+ attribute)
23
+ #
24
+ # If password confirmation validation is not needed, simply leave out the
25
+ # value for +password_confirmation+ (i.e. don't provide a form field for
26
+ # it). When this attribute has a +nil+ value, the validation will not be
27
+ # triggered.
18
28
  #
19
- # If you don't need the confirmation validation, just don't set any
20
- # value to the password_confirmation attribute and the validation
21
- # will not be triggered.
29
+ # For further customizability, it is possible to supress the default
30
+ # validations by passing <tt>validations: false</tt> as an argument.
22
31
  #
23
- # You need to add bcrypt (~> 3.1.7) to Gemfile to use #has_secure_password:
32
+ # Add bcrypt (~> 3.1.7) to Gemfile to use #has_secure_password:
24
33
  #
25
34
  # gem 'bcrypt', '~> 3.1.7'
26
35
  #
@@ -52,11 +61,11 @@ module ActiveModel
52
61
  raise
53
62
  end
54
63
 
55
- attr_reader :password
56
-
57
64
  include InstanceMethodsOnActivation
58
65
 
59
66
  if options.fetch(:validations, true)
67
+ include ActiveModel::Validations
68
+
60
69
  # This ensures the model has a password by checking whether the password_digest
61
70
  # is present, so that this works with both new and existing records. However,
62
71
  # when there is an error, the message is added to the password attribute instead
@@ -65,9 +74,11 @@ module ActiveModel
65
74
  record.errors.add(:password, :blank) unless record.password_digest.present?
66
75
  end
67
76
 
77
+ validates_length_of :password, maximum: ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED
68
78
  validates_confirmation_of :password, if: ->{ password.present? }
69
79
  end
70
80
 
81
+ # This code is necessary as long as the protected_attributes gem is supported.
71
82
  if respond_to?(:attributes_protected_by_default)
72
83
  def self.attributes_protected_by_default #:nodoc:
73
84
  super + ['password_digest']
@@ -91,8 +102,10 @@ module ActiveModel
91
102
  BCrypt::Password.new(password_digest) == unencrypted_password && self
92
103
  end
93
104
 
105
+ attr_reader :password
106
+
94
107
  # Encrypts the password into the +password_digest+ attribute, only if the
95
- # new password is not blank.
108
+ # new password is not empty.
96
109
  #
97
110
  # class User < ActiveRecord::Base
98
111
  # has_secure_password validations: false
@@ -106,7 +119,7 @@ module ActiveModel
106
119
  def password=(unencrypted_password)
107
120
  if unencrypted_password.nil?
108
121
  self.password_digest = nil
109
- elsif unencrypted_password.present?
122
+ elsif !unencrypted_password.empty?
110
123
  @password = unencrypted_password
111
124
  cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
112
125
  self.password_digest = BCrypt::Password.create(unencrypted_password, cost: cost)
@@ -4,7 +4,7 @@ require 'active_support/core_ext/hash/slice'
4
4
  module ActiveModel
5
5
  # == Active \Model \Serialization
6
6
  #
7
- # Provides a basic serialization to a serializable_hash for your object.
7
+ # Provides a basic serialization to a serializable_hash for your objects.
8
8
  #
9
9
  # A minimal implementation could be:
10
10
  #
@@ -25,14 +25,14 @@ module ActiveModel
25
25
  # person.name = "Bob"
26
26
  # person.serializable_hash # => {"name"=>"Bob"}
27
27
  #
28
- # You need to declare an attributes hash which contains the attributes you
29
- # want to serialize. Attributes must be strings, not symbols. When called,
30
- # serializable hash will use instance methods that match the name of the
31
- # attributes hash's keys. In order to override this behavior, take a look at
32
- # the private method +read_attribute_for_serialization+.
28
+ # An +attributes+ hash must be defined and should contain any attributes you
29
+ # need to be serialized. Attributes must be strings, not symbols.
30
+ # When called, serializable hash will use instance methods that match the name
31
+ # of the attributes hash's keys. In order to override this behavior, take a look
32
+ # at the private method +read_attribute_for_serialization+.
33
33
  #
34
- # Most of the time though, you will want to include the JSON or XML
35
- # serializations. Both of these modules automatically include the
34
+ # Most of the time though, either the JSON or XML serializations are needed.
35
+ # Both of these modules automatically include the
36
36
  # <tt>ActiveModel::Serialization</tt> module, so there is no need to
37
37
  # explicitly include it.
38
38
  #
@@ -10,7 +10,7 @@ module ActiveModel
10
10
  included do
11
11
  extend ActiveModel::Naming
12
12
 
13
- class_attribute :include_root_in_json, instance_writer: false
13
+ class_attribute :include_root_in_json
14
14
  self.include_root_in_json = false
15
15
  end
16
16
 
@@ -93,7 +93,7 @@ module ActiveModel
93
93
  end
94
94
 
95
95
  if root
96
- root = self.class.model_name.element if root == true
96
+ root = model_name.element if root == true
97
97
  { root => serializable_hash(options) }
98
98
  else
99
99
  serializable_hash(options)
@@ -84,7 +84,7 @@ module ActiveModel
84
84
  @builder = options[:builder]
85
85
  @builder.instruct! unless options[:skip_instruct]
86
86
 
87
- root = (options[:root] || @serializable.class.model_name.element).to_s
87
+ root = (options[:root] || @serializable.model_name.element).to_s
88
88
  root = ActiveSupport::XmlMini.rename_key(root, options)
89
89
 
90
90
  args = [root]
@@ -39,6 +39,7 @@ module ActiveModel
39
39
  extend ActiveSupport::Concern
40
40
 
41
41
  included do
42
+ extend ActiveModel::Naming
42
43
  extend ActiveModel::Callbacks
43
44
  extend ActiveModel::Translation
44
45
 
@@ -46,10 +47,9 @@ module ActiveModel
46
47
  include HelperMethods
47
48
 
48
49
  attr_accessor :validation_context
49
- private :validation_context=
50
50
  define_callbacks :validate, scope: :name
51
51
 
52
- class_attribute :_validators, instance_writer: false
52
+ class_attribute :_validators
53
53
  self._validators = Hash.new { |h,k| h[k] = [] }
54
54
  end
55
55
 
@@ -142,6 +142,11 @@ module ActiveModel
142
142
  # value.
143
143
  def validate(*args, &block)
144
144
  options = args.extract_options!
145
+
146
+ if args.all? { |arg| arg.is_a?(Symbol) }
147
+ options.assert_valid_keys([:on, :if, :unless])
148
+ end
149
+
145
150
  if options.key?(:on)
146
151
  options = options.dup
147
152
  options[:if] = Array(options[:if])
@@ -149,6 +154,7 @@ module ActiveModel
149
154
  Array(options[:on]).include?(o.validation_context)
150
155
  }
151
156
  end
157
+
152
158
  args << options
153
159
  set_callback(:validate, *args, &block)
154
160
  end
@@ -286,6 +292,8 @@ module ActiveModel
286
292
  # Runs all the specified validations and returns +true+ if no errors were
287
293
  # added otherwise +false+.
288
294
  #
295
+ # Aliased as validate.
296
+ #
289
297
  # class Person
290
298
  # include ActiveModel::Validations
291
299
  #
@@ -320,6 +328,8 @@ module ActiveModel
320
328
  self.validation_context = current_context
321
329
  end
322
330
 
331
+ alias_method :validate, :valid?
332
+
323
333
  # Performs the opposite of <tt>valid?</tt>. Returns +true+ if errors were
324
334
  # added, +false+ otherwise.
325
335
  #
@@ -30,7 +30,7 @@ module ActiveModel
30
30
  return
31
31
  end
32
32
 
33
- if options[:only_integer]
33
+ if allow_only_integer?(record)
34
34
  unless value = parse_raw_value_as_an_integer(raw_value)
35
35
  record.errors.add(attr_name, :not_an_integer, filtered_options(raw_value))
36
36
  return
@@ -75,6 +75,17 @@ module ActiveModel
75
75
  filtered[:value] = value
76
76
  filtered
77
77
  end
78
+
79
+ def allow_only_integer?(record)
80
+ case options[:only_integer]
81
+ when Symbol
82
+ record.send(options[:only_integer])
83
+ when Proc
84
+ options[:only_integer].call(record)
85
+ else
86
+ options[:only_integer]
87
+ end
88
+ end
78
89
  end
79
90
 
80
91
  module HelperMethods
@@ -121,6 +132,7 @@ module ActiveModel
121
132
  # * <tt>:equal_to</tt>
122
133
  # * <tt>:less_than</tt>
123
134
  # * <tt>:less_than_or_equal_to</tt>
135
+ # * <tt>:only_integer</tt>
124
136
  #
125
137
  # For example:
126
138
  #
@@ -53,7 +53,7 @@ module ActiveModel
53
53
  #
54
54
  # Configuration options:
55
55
  # * <tt>:on</tt> - Specifies when this validation is active
56
- # (<tt>:create</tt> or <tt>:update</tt>.
56
+ # (<tt>:create</tt> or <tt>:update</tt>).
57
57
  # * <tt>:if</tt> - Specifies a method, proc or string to call to determine
58
58
  # if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
59
59
  # or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>).
@@ -106,7 +106,6 @@ module ActiveModel
106
106
  # Accepts options that will be made available through the +options+ reader.
107
107
  def initialize(options = {})
108
108
  @options = options.except(:class).freeze
109
- deprecated_setup(options)
110
109
  end
111
110
 
112
111
  # Returns the kind for this validator.
@@ -122,21 +121,6 @@ module ActiveModel
122
121
  def validate(record)
123
122
  raise NotImplementedError, "Subclasses must implement a validate(record) method."
124
123
  end
125
-
126
- private
127
- def deprecated_setup(options) # TODO: remove me in 4.2.
128
- return unless respond_to?(:setup)
129
- ActiveSupport::Deprecation.warn "The `Validator#setup` instance method is deprecated and will be removed on Rails 4.2. Do your setup in the constructor instead:
130
-
131
- class MyValidator < ActiveModel::Validator
132
- def initialize(options={})
133
- super
134
- options[:class].send :attr_accessor, :custom_attribute
135
- end
136
- end
137
- "
138
- setup(options[:class])
139
- end
140
124
  end
141
125
 
142
126
  # +EachValidator+ is a validator which iterates through the attributes given
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activemodel
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.16
4
+ version: 4.2.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Heinemeier Hansson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-12 00:00:00.000000000 Z
11
+ date: 2014-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 4.1.16
19
+ version: 4.2.0.beta1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 4.1.16
26
+ version: 4.2.0.beta1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: builder
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -99,12 +99,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
99
  version: 1.9.3
100
100
  required_rubygems_version: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - ">="
102
+ - - ">"
103
103
  - !ruby/object:Gem::Version
104
- version: '0'
104
+ version: 1.3.1
105
105
  requirements: []
106
106
  rubyforge_project:
107
- rubygems_version: 2.4.5.1
107
+ rubygems_version: 2.2.2
108
108
  signing_key:
109
109
  specification_version: 4
110
110
  summary: A toolkit for building modeling frameworks (part of Rails).