activemodel 5.0.7.2 → 5.1.0.beta1

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