activemodel 5.0.7.2 → 5.1.0.beta1

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.
Files changed (60) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +15 -219
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_model.rb +11 -12
  6. data/lib/active_model/attribute_assignment.rb +11 -11
  7. data/lib/active_model/attribute_methods.rb +13 -15
  8. data/lib/active_model/callbacks.rb +19 -20
  9. data/lib/active_model/conversion.rb +12 -3
  10. data/lib/active_model/dirty.rb +14 -14
  11. data/lib/active_model/errors.rb +27 -103
  12. data/lib/active_model/forbidden_attributes_protection.rb +1 -1
  13. data/lib/active_model/gem_version.rb +3 -3
  14. data/lib/active_model/lint.rb +0 -1
  15. data/lib/active_model/model.rb +3 -4
  16. data/lib/active_model/naming.rb +9 -10
  17. data/lib/active_model/secure_password.rb +1 -1
  18. data/lib/active_model/serialization.rb +2 -2
  19. data/lib/active_model/serializers/json.rb +2 -2
  20. data/lib/active_model/translation.rb +2 -3
  21. data/lib/active_model/type.rb +15 -19
  22. data/lib/active_model/type/big_integer.rb +4 -4
  23. data/lib/active_model/type/binary.rb +1 -1
  24. data/lib/active_model/type/boolean.rb +20 -9
  25. data/lib/active_model/type/date.rb +25 -25
  26. data/lib/active_model/type/date_time.rb +21 -21
  27. data/lib/active_model/type/decimal.rb +35 -39
  28. data/lib/active_model/type/float.rb +17 -8
  29. data/lib/active_model/type/helpers.rb +4 -4
  30. data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +2 -2
  31. data/lib/active_model/type/helpers/mutable.rb +2 -2
  32. data/lib/active_model/type/helpers/numeric.rb +18 -17
  33. data/lib/active_model/type/helpers/time_value.rb +23 -23
  34. data/lib/active_model/type/immutable_string.rb +9 -8
  35. data/lib/active_model/type/integer.rb +23 -21
  36. data/lib/active_model/type/registry.rb +12 -8
  37. data/lib/active_model/type/string.rb +1 -6
  38. data/lib/active_model/type/time.rb +15 -11
  39. data/lib/active_model/type/value.rb +6 -6
  40. data/lib/active_model/validations.rb +9 -12
  41. data/lib/active_model/validations/absence.rb +1 -1
  42. data/lib/active_model/validations/acceptance.rb +41 -40
  43. data/lib/active_model/validations/callbacks.rb +4 -7
  44. data/lib/active_model/validations/clusivity.rb +7 -7
  45. data/lib/active_model/validations/confirmation.rb +15 -16
  46. data/lib/active_model/validations/exclusion.rb +1 -2
  47. data/lib/active_model/validations/format.rb +24 -24
  48. data/lib/active_model/validations/inclusion.rb +1 -2
  49. data/lib/active_model/validations/length.rb +6 -42
  50. data/lib/active_model/validations/numericality.rb +3 -11
  51. data/lib/active_model/validations/presence.rb +1 -2
  52. data/lib/active_model/validations/validates.rb +6 -6
  53. data/lib/active_model/validations/with.rb +4 -2
  54. data/lib/active_model/validator.rb +5 -6
  55. data/lib/active_model/version.rb +1 -1
  56. metadata +8 -11
  57. data/lib/active_model/test_case.rb +0 -4
  58. data/lib/active_model/type/decimal_without_scale.rb +0 -11
  59. data/lib/active_model/type/text.rb +0 -11
  60. data/lib/active_model/type/unsigned_integer.rb +0 -15
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/array/extract_options'
1
+ require "active_support/core_ext/array/extract_options"
2
2
 
3
3
  module ActiveModel
4
4
  # == Active \Model \Callbacks
@@ -103,7 +103,6 @@ module ActiveModel
103
103
  def define_model_callbacks(*callbacks)
104
104
  options = callbacks.extract_options!
105
105
  options = {
106
- terminator: deprecated_false_terminator,
107
106
  skip_after_callbacks_if_terminated: true,
108
107
  scope: [:kind, :name],
109
108
  only: [:before, :around, :after]
@@ -122,28 +121,28 @@ module ActiveModel
122
121
 
123
122
  private
124
123
 
125
- def _define_before_model_callback(klass, callback) #:nodoc:
126
- klass.define_singleton_method("before_#{callback}") do |*args, &block|
127
- set_callback(:"#{callback}", :before, *args, &block)
124
+ def _define_before_model_callback(klass, callback)
125
+ klass.define_singleton_method("before_#{callback}") do |*args, &block|
126
+ set_callback(:"#{callback}", :before, *args, &block)
127
+ end
128
128
  end
129
- end
130
129
 
131
- def _define_around_model_callback(klass, callback) #:nodoc:
132
- klass.define_singleton_method("around_#{callback}") do |*args, &block|
133
- set_callback(:"#{callback}", :around, *args, &block)
130
+ def _define_around_model_callback(klass, callback)
131
+ klass.define_singleton_method("around_#{callback}") do |*args, &block|
132
+ set_callback(:"#{callback}", :around, *args, &block)
133
+ end
134
134
  end
135
- end
136
135
 
137
- def _define_after_model_callback(klass, callback) #:nodoc:
138
- klass.define_singleton_method("after_#{callback}") do |*args, &block|
139
- options = args.extract_options!
140
- options[:prepend] = true
141
- conditional = ActiveSupport::Callbacks::Conditionals::Value.new { |v|
142
- v != false
143
- }
144
- options[:if] = Array(options[:if]) << conditional
145
- set_callback(:"#{callback}", :after, *(args << options), &block)
136
+ def _define_after_model_callback(klass, callback)
137
+ klass.define_singleton_method("after_#{callback}") do |*args, &block|
138
+ options = args.extract_options!
139
+ options[:prepend] = true
140
+ conditional = ActiveSupport::Callbacks::Conditionals::Value.new { |v|
141
+ v != false
142
+ }
143
+ options[:if] = Array(options[:if]) << conditional
144
+ set_callback(:"#{callback}", :after, *(args << options), &block)
145
+ end
146
146
  end
147
- end
148
147
  end
149
148
  end
@@ -46,9 +46,13 @@ module ActiveModel
46
46
  # class Person
47
47
  # include ActiveModel::Conversion
48
48
  # attr_accessor :id
49
+ #
50
+ # def initialize(id)
51
+ # @id = id
52
+ # end
49
53
  # end
50
54
  #
51
- # person = Person.create(id: 1)
55
+ # person = Person.new(1)
52
56
  # person.to_key # => [1]
53
57
  def to_key
54
58
  key = respond_to?(:id) && id
@@ -61,15 +65,20 @@ module ActiveModel
61
65
  # class Person
62
66
  # include ActiveModel::Conversion
63
67
  # attr_accessor :id
68
+ #
69
+ # def initialize(id)
70
+ # @id = id
71
+ # end
72
+ #
64
73
  # def persisted?
65
74
  # true
66
75
  # end
67
76
  # end
68
77
  #
69
- # person = Person.create(id: 1)
78
+ # person = Person.new(1)
70
79
  # person.to_param # => "1"
71
80
  def to_param
72
- (persisted? && key = to_key) ? key.join('-') : nil
81
+ (persisted? && key = to_key) ? key.join("-") : nil
73
82
  end
74
83
 
75
84
  # Returns a +string+ identifying the path associated with the object.
@@ -1,5 +1,5 @@
1
- require 'active_support/hash_with_indifferent_access'
2
- require 'active_support/core_ext/object/duplicable'
1
+ require "active_support/hash_with_indifferent_access"
2
+ require "active_support/core_ext/object/duplicable"
3
3
 
4
4
  module ActiveModel
5
5
  # == Active \Model \Dirty
@@ -26,8 +26,8 @@ module ActiveModel
26
26
  #
27
27
  # define_attribute_methods :name
28
28
  #
29
- # def initialize(name)
30
- # @name = name
29
+ # def initialize
30
+ # @name = nil
31
31
  # end
32
32
  #
33
33
  # def name
@@ -58,7 +58,7 @@ module ActiveModel
58
58
  #
59
59
  # A newly instantiated +Person+ object is unchanged:
60
60
  #
61
- # person = Person.new("Uncle Bob")
61
+ # person = Person.new
62
62
  # person.changed? # => false
63
63
  #
64
64
  # Change the name:
@@ -66,11 +66,11 @@ module ActiveModel
66
66
  # person.name = 'Bob'
67
67
  # person.changed? # => true
68
68
  # person.name_changed? # => true
69
- # person.name_changed?(from: "Uncle Bob", to: "Bob") # => true
70
- # person.name_was # => "Uncle Bob"
71
- # person.name_change # => ["Uncle Bob", "Bob"]
69
+ # person.name_changed?(from: nil, to: "Bob") # => true
70
+ # person.name_was # => nil
71
+ # person.name_change # => [nil, "Bob"]
72
72
  # person.name = 'Bill'
73
- # person.name_change # => ["Uncle Bob", "Bill"]
73
+ # person.name_change # => [nil, "Bill"]
74
74
  #
75
75
  # Save the changes:
76
76
  #
@@ -80,9 +80,9 @@ module ActiveModel
80
80
  #
81
81
  # Reset the changes:
82
82
  #
83
- # person.previous_changes # => {"name" => ["Uncle Bob", "Bill"]}
83
+ # person.previous_changes # => {"name" => [nil, "Bill"]}
84
84
  # person.name_previously_changed? # => true
85
- # person.name_previous_change # => ["Uncle Bob", "Bill"]
85
+ # person.name_previous_change # => [nil, "Bill"]
86
86
  # person.reload!
87
87
  # person.previous_changes # => {}
88
88
  #
@@ -123,9 +123,9 @@ module ActiveModel
123
123
  private_constant :OPTION_NOT_GIVEN
124
124
 
125
125
  included do
126
- attribute_method_suffix '_changed?', '_change', '_will_change!', '_was'
127
- attribute_method_suffix '_previously_changed?', '_previous_change'
128
- attribute_method_affix prefix: 'restore_', suffix: '!'
126
+ attribute_method_suffix "_changed?", "_change", "_will_change!", "_was"
127
+ attribute_method_suffix "_previously_changed?", "_previous_change"
128
+ attribute_method_affix prefix: "restore_", suffix: "!"
129
129
  end
130
130
 
131
131
  # Returns +true+ if any of the attributes have unsaved changes, +false+ otherwise.
@@ -1,7 +1,7 @@
1
- require 'active_support/core_ext/array/conversions'
2
- require 'active_support/core_ext/string/inflections'
3
- require 'active_support/core_ext/object/deep_dup'
4
- require 'active_support/core_ext/string/filters'
1
+ require "active_support/core_ext/array/conversions"
2
+ require "active_support/core_ext/string/inflections"
3
+ require "active_support/core_ext/object/deep_dup"
4
+ require "active_support/core_ext/string/filters"
5
5
 
6
6
  module ActiveModel
7
7
  # == Active \Model \Errors
@@ -110,49 +110,21 @@ module ActiveModel
110
110
  # person.errors.include?(:name) # => true
111
111
  # person.errors.include?(:age) # => false
112
112
  def include?(attribute)
113
+ attribute = attribute.to_sym
113
114
  messages.key?(attribute) && messages[attribute].present?
114
115
  end
115
116
  alias :has_key? :include?
116
117
  alias :key? :include?
117
118
 
118
- # Get messages for +key+.
119
- #
120
- # person.errors.messages # => {:name=>["cannot be nil"]}
121
- # person.errors.get(:name) # => ["cannot be nil"]
122
- # person.errors.get(:age) # => []
123
- def get(key)
124
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
125
- ActiveModel::Errors#get is deprecated and will be removed in Rails 5.1.
126
-
127
- To achieve the same use model.errors[:#{key}].
128
- MESSAGE
129
-
130
- messages[key]
131
- end
132
-
133
- # Set messages for +key+ to +value+.
134
- #
135
- # person.errors[:name] # => ["cannot be nil"]
136
- # person.errors.set(:name, ["can't be nil"])
137
- # person.errors[:name] # => ["can't be nil"]
138
- def set(key, value)
139
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
140
- ActiveModel::Errors#set is deprecated and will be removed in Rails 5.1.
141
-
142
- Use model.errors.add(:#{key}, #{value.inspect}) instead.
143
- MESSAGE
144
-
145
- messages[key] = value
146
- end
147
-
148
119
  # Delete messages for +key+. Returns the deleted messages.
149
120
  #
150
121
  # person.errors[:name] # => ["cannot be nil"]
151
122
  # person.errors.delete(:name) # => ["cannot be nil"]
152
123
  # person.errors[:name] # => []
153
124
  def delete(key)
154
- details.delete(key)
155
- messages.delete(key)
125
+ attribute = key.to_sym
126
+ details.delete(attribute)
127
+ messages.delete(attribute)
156
128
  end
157
129
 
158
130
  # When passed a symbol or a name of a method, returns an array of errors
@@ -173,20 +145,6 @@ module ActiveModel
173
145
  messages[attribute.to_sym]
174
146
  end
175
147
 
176
- # Adds to the supplied attribute the supplied error message.
177
- #
178
- # person.errors[:name] = "must be set"
179
- # person.errors[:name] # => ['must be set']
180
- def []=(attribute, error)
181
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
182
- ActiveModel::Errors#[]= is deprecated and will be removed in Rails 5.1.
183
-
184
- Use model.errors.add(:#{attribute}, #{error.inspect}) instead.
185
- MESSAGE
186
-
187
- messages[attribute.to_sym] << error
188
- end
189
-
190
148
  # Iterates through each error key, value pair in the error messages hash.
191
149
  # Yields the attribute and the error for that attribute. If the attribute
192
150
  # has more than one error message, yields once for each error message.
@@ -255,7 +213,7 @@ module ActiveModel
255
213
  # # <error>name can't be blank</error>
256
214
  # # <error>name must be specified</error>
257
215
  # # </errors>
258
- def to_xml(options={})
216
+ def to_xml(options = {})
259
217
  to_a.to_xml({ root: "errors", skip_types: true }.merge!(options))
260
218
  end
261
219
 
@@ -265,7 +223,7 @@ module ActiveModel
265
223
  #
266
224
  # person.errors.as_json # => {:name=>["cannot be nil"]}
267
225
  # person.errors.as_json(full_messages: true) # => {:name=>["name cannot be nil"]}
268
- def as_json(options=nil)
226
+ def as_json(options = nil)
269
227
  to_hash(options && options[:full_messages])
270
228
  end
271
229
 
@@ -276,11 +234,11 @@ module ActiveModel
276
234
  # person.errors.to_hash(true) # => {:name=>["name cannot be nil"]}
277
235
  def to_hash(full_messages = false)
278
236
  if full_messages
279
- self.messages.each_with_object({}) do |(attribute, array), messages|
237
+ messages.each_with_object({}) do |(attribute, array), messages|
280
238
  messages[attribute] = array.map { |message| full_message(attribute, message) }
281
239
  end
282
240
  else
283
- without_default_proc(self.messages)
241
+ without_default_proc(messages)
284
242
  end
285
243
  end
286
244
 
@@ -310,9 +268,9 @@ module ActiveModel
310
268
  # <tt>:strict</tt> option can also be set to any other exception.
311
269
  #
312
270
  # person.errors.add(:name, :invalid, strict: true)
313
- # # => ActiveModel::StrictValidationFailed: name is invalid
271
+ # # => ActiveModel::StrictValidationFailed: Name is invalid
314
272
  # person.errors.add(:name, :invalid, strict: NameIsInvalid)
315
- # # => NameIsInvalid: name is invalid
273
+ # # => NameIsInvalid: Name is invalid
316
274
  #
317
275
  # person.errors.messages # => {}
318
276
  #
@@ -338,49 +296,6 @@ module ActiveModel
338
296
  messages[attribute.to_sym] << message
339
297
  end
340
298
 
341
- # Will add an error message to each of the attributes in +attributes+
342
- # that is empty.
343
- #
344
- # person.errors.add_on_empty(:name)
345
- # person.errors.messages
346
- # # => {:name=>["can't be empty"]}
347
- def add_on_empty(attributes, options = {})
348
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
349
- ActiveModel::Errors#add_on_empty is deprecated and will be removed in Rails 5.1.
350
-
351
- To achieve the same use:
352
-
353
- errors.add(attribute, :empty, options) if value.nil? || value.empty?
354
- MESSAGE
355
-
356
- Array(attributes).each do |attribute|
357
- value = @base.send(:read_attribute_for_validation, attribute)
358
- is_empty = value.respond_to?(:empty?) ? value.empty? : false
359
- add(attribute, :empty, options) if value.nil? || is_empty
360
- end
361
- end
362
-
363
- # Will add an error message to each of the attributes in +attributes+ that
364
- # is blank (using Object#blank?).
365
- #
366
- # person.errors.add_on_blank(:name)
367
- # person.errors.messages
368
- # # => {:name=>["can't be blank"]}
369
- def add_on_blank(attributes, options = {})
370
- ActiveSupport::Deprecation.warn(<<-MESSAGE.squish)
371
- ActiveModel::Errors#add_on_blank is deprecated and will be removed in Rails 5.1.
372
-
373
- To achieve the same use:
374
-
375
- errors.add(attribute, :blank, options) if value.blank?
376
- MESSAGE
377
-
378
- Array(attributes).each do |attribute|
379
- value = @base.send(:read_attribute_for_validation, attribute)
380
- add(attribute, :blank, options) if value.blank?
381
- end
382
- end
383
-
384
299
  # Returns +true+ if an error on the attribute with the given message is
385
300
  # present, or +false+ otherwise. +message+ is treated the same as for +add+.
386
301
  #
@@ -429,6 +344,7 @@ module ActiveModel
429
344
  # person.errors.full_messages_for(:name)
430
345
  # # => ["Name is too short (minimum is 5 characters)", "Name can't be blank"]
431
346
  def full_messages_for(attribute)
347
+ attribute = attribute.to_sym
432
348
  messages[attribute].map { |message| full_message(attribute, message) }
433
349
  end
434
350
 
@@ -437,13 +353,12 @@ module ActiveModel
437
353
  # person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
438
354
  def full_message(attribute, message)
439
355
  return message if attribute == :base
440
- attr_name = attribute.to_s.tr('.', '_').humanize
356
+ attr_name = attribute.to_s.tr(".", "_").humanize
441
357
  attr_name = @base.class.human_attribute_name(attribute, default: attr_name)
442
- I18n.t(:"errors.format", {
358
+ I18n.t(:"errors.format",
443
359
  default: "%{attribute} %{message}",
444
360
  attribute: attr_name,
445
- message: message
446
- })
361
+ message: message)
447
362
  end
448
363
 
449
364
  # Translates an error message in its default scope
@@ -570,6 +485,15 @@ module ActiveModel
570
485
  end
571
486
 
572
487
  # Raised when unknown attributes are supplied via mass assignment.
488
+ #
489
+ # class Person
490
+ # include ActiveModel::AttributeAssignment
491
+ # include ActiveModel::Validations
492
+ # end
493
+ #
494
+ # person = Person.new
495
+ # person.assign_attributes(name: 'Gorby')
496
+ # # => ActiveModel::UnknownAttributeError: unknown attribute 'name' for Person.
573
497
  class UnknownAttributeError < NoMethodError
574
498
  attr_reader :record, :attribute
575
499
 
@@ -15,7 +15,7 @@ module ActiveModel
15
15
  end
16
16
 
17
17
  module ForbiddenAttributesProtection # :nodoc:
18
- protected
18
+ private
19
19
  def sanitize_for_mass_assignment(attributes)
20
20
  if attributes.respond_to?(:permitted?)
21
21
  raise ActiveModel::ForbiddenAttributesError if !attributes.permitted?
@@ -6,9 +6,9 @@ module ActiveModel
6
6
 
7
7
  module VERSION
8
8
  MAJOR = 5
9
- MINOR = 0
10
- TINY = 7
11
- PRE = "2"
9
+ MINOR = 1
10
+ TINY = 0
11
+ PRE = "beta1"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -20,7 +20,6 @@ module ActiveModel
20
20
  # to <tt>to_model</tt>. It is perfectly fine for <tt>to_model</tt> to return
21
21
  # +self+.
22
22
  module Tests
23
-
24
23
  # Passes if the object's model responds to <tt>to_key</tt> and if calling
25
24
  # this method returns +nil+ when the object is not persisted.
26
25
  # Fails otherwise.
@@ -1,12 +1,11 @@
1
1
  module ActiveModel
2
-
3
2
  # == Active \Model \Basic \Model
4
3
  #
5
4
  # Includes the required interface for an object to interact with
6
- # <tt>ActionPack</tt>, using different <tt>ActiveModel</tt> modules.
5
+ # Action Pack and Action View, using different Active Model modules.
7
6
  # It includes model name introspections, conversions, translations and
8
7
  # validations. Besides that, it allows you to initialize the object with a
9
- # hash of attributes, pretty much like <tt>ActiveRecord</tt> does.
8
+ # hash of attributes, pretty much like Active Record does.
10
9
  #
11
10
  # A minimal implementation could be:
12
11
  #
@@ -76,7 +75,7 @@ module ActiveModel
76
75
  # person = Person.new(name: 'bob', age: '18')
77
76
  # person.name # => "bob"
78
77
  # person.age # => "18"
79
- def initialize(attributes={})
78
+ def initialize(attributes = {})
80
79
  assign_attributes(attributes) if attributes
81
80
 
82
81
  super()
@@ -1,7 +1,6 @@
1
- require 'active_support/core_ext/hash/except'
2
- require 'active_support/core_ext/module/introspection'
3
- require 'active_support/core_ext/module/remove_method'
4
- require 'active_support/core_ext/module/delegation'
1
+ require "active_support/core_ext/hash/except"
2
+ require "active_support/core_ext/module/introspection"
3
+ require "active_support/core_ext/module/remove_method"
5
4
 
6
5
  module ActiveModel
7
6
  class Name
@@ -149,7 +148,7 @@ module ActiveModel
149
148
 
150
149
  raise ArgumentError, "Class name cannot be blank. You need to supply a name argument when anonymous class given" if @name.blank?
151
150
 
152
- @unnamespaced = @name.sub(/^#{namespace.name}::/, '') if namespace
151
+ @unnamespaced = @name.sub(/^#{namespace.name}::/, "") if namespace
153
152
  @klass = klass
154
153
  @singular = _singularize(@name)
155
154
  @plural = ActiveSupport::Inflector.pluralize(@singular)
@@ -174,7 +173,7 @@ module ActiveModel
174
173
  # BlogPost.model_name.human # => "Blog post"
175
174
  #
176
175
  # Specify +options+ with additional translating options.
177
- def human(options={})
176
+ def human(options = {})
178
177
  return @human unless @klass.respond_to?(:lookup_ancestors) &&
179
178
  @klass.respond_to?(:i18n_scope)
180
179
 
@@ -191,9 +190,9 @@ module ActiveModel
191
190
 
192
191
  private
193
192
 
194
- def _singularize(string)
195
- ActiveSupport::Inflector.underscore(string).tr('/'.freeze, '_'.freeze)
196
- end
193
+ def _singularize(string)
194
+ ActiveSupport::Inflector.underscore(string).tr("/".freeze, "_".freeze)
195
+ end
197
196
  end
198
197
 
199
198
  # == Active \Model \Naming
@@ -235,7 +234,7 @@ module ActiveModel
235
234
  # Person.model_name.plural # => "people"
236
235
  def model_name
237
236
  @_model_name ||= begin
238
- namespace = self.parents.detect do |n|
237
+ namespace = parents.detect do |n|
239
238
  n.respond_to?(:use_relative_model_naming?) && n.use_relative_model_naming?
240
239
  end
241
240
  ActiveModel::Name.new(self, namespace)