activemodel 7.0.8.7 → 7.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +132 -226
- data/MIT-LICENSE +1 -1
- data/README.rdoc +9 -9
- data/lib/active_model/access.rb +16 -0
- data/lib/active_model/api.rb +5 -5
- data/lib/active_model/attribute/user_provided_default.rb +4 -0
- data/lib/active_model/attribute.rb +26 -1
- data/lib/active_model/attribute_assignment.rb +1 -1
- data/lib/active_model/attribute_methods.rb +102 -63
- data/lib/active_model/attribute_registration.rb +77 -0
- data/lib/active_model/attribute_set.rb +9 -0
- data/lib/active_model/attributes.rb +62 -45
- data/lib/active_model/callbacks.rb +5 -5
- data/lib/active_model/conversion.rb +14 -4
- data/lib/active_model/deprecator.rb +7 -0
- data/lib/active_model/dirty.rb +134 -13
- data/lib/active_model/error.rb +4 -3
- data/lib/active_model/errors.rb +17 -12
- data/lib/active_model/forbidden_attributes_protection.rb +2 -0
- data/lib/active_model/gem_version.rb +4 -4
- data/lib/active_model/lint.rb +1 -1
- data/lib/active_model/locale/en.yml +4 -3
- data/lib/active_model/model.rb +26 -2
- data/lib/active_model/naming.rb +29 -10
- data/lib/active_model/railtie.rb +4 -0
- data/lib/active_model/secure_password.rb +61 -23
- data/lib/active_model/serialization.rb +3 -3
- data/lib/active_model/serializers/json.rb +1 -1
- data/lib/active_model/translation.rb +18 -16
- data/lib/active_model/type/big_integer.rb +23 -1
- data/lib/active_model/type/binary.rb +7 -1
- data/lib/active_model/type/boolean.rb +11 -9
- data/lib/active_model/type/date.rb +28 -2
- data/lib/active_model/type/date_time.rb +45 -3
- data/lib/active_model/type/decimal.rb +39 -1
- data/lib/active_model/type/float.rb +30 -1
- data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +5 -1
- data/lib/active_model/type/helpers/numeric.rb +4 -0
- data/lib/active_model/type/helpers/time_value.rb +28 -12
- data/lib/active_model/type/immutable_string.rb +37 -1
- data/lib/active_model/type/integer.rb +44 -1
- data/lib/active_model/type/serialize_cast_value.rb +47 -0
- data/lib/active_model/type/string.rb +9 -1
- data/lib/active_model/type/time.rb +48 -7
- data/lib/active_model/type/value.rb +17 -1
- data/lib/active_model/type.rb +1 -0
- data/lib/active_model/validations/absence.rb +1 -1
- data/lib/active_model/validations/acceptance.rb +1 -1
- data/lib/active_model/validations/callbacks.rb +4 -4
- data/lib/active_model/validations/clusivity.rb +5 -8
- data/lib/active_model/validations/comparability.rb +0 -11
- data/lib/active_model/validations/comparison.rb +15 -7
- data/lib/active_model/validations/confirmation.rb +1 -1
- data/lib/active_model/validations/format.rb +6 -7
- data/lib/active_model/validations/length.rb +10 -8
- data/lib/active_model/validations/numericality.rb +35 -23
- data/lib/active_model/validations/presence.rb +2 -2
- data/lib/active_model/validations/resolve_value.rb +26 -0
- data/lib/active_model/validations/validates.rb +4 -4
- data/lib/active_model/validations/with.rb +9 -2
- data/lib/active_model/validations.rb +45 -10
- data/lib/active_model/validator.rb +7 -5
- data/lib/active_model/version.rb +1 -1
- data/lib/active_model.rb +5 -1
- metadata +18 -13
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module ActiveModel
         | 
| 4 | 
            -
              #  | 
| 4 | 
            +
              # = Active \Model \Conversion
         | 
| 5 5 | 
             
              #
         | 
| 6 6 | 
             
              # Handles default conversions: to_model, to_key, to_param, and to_partial_path.
         | 
| 7 7 | 
             
              #
         | 
| @@ -24,6 +24,14 @@ module ActiveModel | |
| 24 24 | 
             
              module Conversion
         | 
| 25 25 | 
             
                extend ActiveSupport::Concern
         | 
| 26 26 |  | 
| 27 | 
            +
                included do
         | 
| 28 | 
            +
                  ##
         | 
| 29 | 
            +
                  # :singleton-method:
         | 
| 30 | 
            +
                  #
         | 
| 31 | 
            +
                  # Accepts a string that will be used as a delimiter of object's key values in the `to_param` method.
         | 
| 32 | 
            +
                  class_attribute :param_delimiter, instance_reader: false, default: "-"
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 27 35 | 
             
                # If your object is already designed to implement all of the \Active \Model
         | 
| 28 36 | 
             
                # you can use the default <tt>:to_model</tt> implementation, which simply
         | 
| 29 37 | 
             
                # returns +self+.
         | 
| @@ -58,7 +66,7 @@ module ActiveModel | |
| 58 66 | 
             
                #   person.to_key # => [1]
         | 
| 59 67 | 
             
                def to_key
         | 
| 60 68 | 
             
                  key = respond_to?(:id) && id
         | 
| 61 | 
            -
                  key ?  | 
| 69 | 
            +
                  key ? Array(key) : nil
         | 
| 62 70 | 
             
                end
         | 
| 63 71 |  | 
| 64 72 | 
             
                # Returns a +string+ representing the object's key suitable for use in URLs,
         | 
| @@ -80,7 +88,7 @@ module ActiveModel | |
| 80 88 | 
             
                #   person = Person.new(1)
         | 
| 81 89 | 
             
                #   person.to_param # => "1"
         | 
| 82 90 | 
             
                def to_param
         | 
| 83 | 
            -
                  (persisted? && key = to_key) ? key.join( | 
| 91 | 
            +
                  (persisted? && (key = to_key) && key.all?) ? key.join(self.class.param_delimiter) : nil
         | 
| 84 92 | 
             
                end
         | 
| 85 93 |  | 
| 86 94 | 
             
                # Returns a +string+ identifying the path associated with the object.
         | 
| @@ -100,7 +108,9 @@ module ActiveModel | |
| 100 108 | 
             
                  # Provide a class level cache for #to_partial_path. This is an
         | 
| 101 109 | 
             
                  # internal method and should not be accessed directly.
         | 
| 102 110 | 
             
                  def _to_partial_path # :nodoc:
         | 
| 103 | 
            -
                    @_to_partial_path ||=  | 
| 111 | 
            +
                    @_to_partial_path ||= if respond_to?(:model_name)
         | 
| 112 | 
            +
                      "#{model_name.collection}/#{model_name.element}"
         | 
| 113 | 
            +
                    else
         | 
| 104 114 | 
             
                      element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(name))
         | 
| 105 115 | 
             
                      collection = ActiveSupport::Inflector.tableize(name)
         | 
| 106 116 | 
             
                      "#{collection}/#{element}"
         | 
    
        data/lib/active_model/dirty.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ | |
| 3 3 | 
             
            require "active_model/attribute_mutation_tracker"
         | 
| 4 4 |  | 
| 5 5 | 
             
            module ActiveModel
         | 
| 6 | 
            -
              #  | 
| 6 | 
            +
              # = Active \Model \Dirty
         | 
| 7 7 | 
             
              #
         | 
| 8 8 | 
             
              # Provides a way to track changes in your object in the same way as
         | 
| 9 9 | 
             
              # Active Record does.
         | 
| @@ -13,8 +13,7 @@ module ActiveModel | |
| 13 13 | 
             
              # * <tt>include ActiveModel::Dirty</tt> in your object.
         | 
| 14 14 | 
             
              # * Call <tt>define_attribute_methods</tt> passing each method you want to
         | 
| 15 15 | 
             
              #   track.
         | 
| 16 | 
            -
              # * Call <tt | 
| 17 | 
            -
              #   attribute.
         | 
| 16 | 
            +
              # * Call <tt>*_will_change!</tt> before each change to the tracked attribute.
         | 
| 18 17 | 
             
              # * Call <tt>changes_applied</tt> after the changes are persisted.
         | 
| 19 18 | 
             
              # * Call <tt>clear_changes_information</tt> when you want to reset the changes
         | 
| 20 19 | 
             
              #   information.
         | 
| @@ -109,20 +108,136 @@ module ActiveModel | |
| 109 108 | 
             
              #   person.changes # => {"name" => ["Bill", "Bob"]}
         | 
| 110 109 | 
             
              #
         | 
| 111 110 | 
             
              # If an attribute is modified in-place then make use of
         | 
| 112 | 
            -
              #  | 
| 111 | 
            +
              # {*_will_change!}[rdoc-label:method-i-2A_will_change-21] to mark that the attribute is changing.
         | 
| 113 112 | 
             
              # Otherwise \Active \Model can't track changes to in-place attributes. Note
         | 
| 114 113 | 
             
              # that Active Record can detect in-place modifications automatically. You do
         | 
| 115 | 
            -
              # not need to call <tt | 
| 114 | 
            +
              # not need to call <tt>*_will_change!</tt> on Active Record models.
         | 
| 116 115 | 
             
              #
         | 
| 117 116 | 
             
              #   person.name_will_change!
         | 
| 118 117 | 
             
              #   person.name_change # => ["Bill", "Bill"]
         | 
| 119 118 | 
             
              #   person.name << 'y'
         | 
| 120 119 | 
             
              #   person.name_change # => ["Bill", "Billy"]
         | 
| 120 | 
            +
              #
         | 
| 121 | 
            +
              # Methods can be invoked as +name_changed?+ or by passing an argument to the
         | 
| 122 | 
            +
              # generic method <tt>attribute_changed?("name")</tt>.
         | 
| 121 123 | 
             
              module Dirty
         | 
| 122 124 | 
             
                extend ActiveSupport::Concern
         | 
| 123 125 | 
             
                include ActiveModel::AttributeMethods
         | 
| 124 126 |  | 
| 125 127 | 
             
                included do
         | 
| 128 | 
            +
                  ##
         | 
| 129 | 
            +
                  # :method: *_previously_changed?
         | 
| 130 | 
            +
                  #
         | 
| 131 | 
            +
                  # :call-seq: *_previously_changed?(**options)
         | 
| 132 | 
            +
                  #
         | 
| 133 | 
            +
                  # This method is generated for each attribute.
         | 
| 134 | 
            +
                  #
         | 
| 135 | 
            +
                  # Returns true if the attribute previously had unsaved changes.
         | 
| 136 | 
            +
                  #
         | 
| 137 | 
            +
                  #   person = Person.new
         | 
| 138 | 
            +
                  #   person.name = 'Britanny'
         | 
| 139 | 
            +
                  #   person.save
         | 
| 140 | 
            +
                  #   person.name_previously_changed? # => true
         | 
| 141 | 
            +
                  #   person.name_previously_changed?(from: nil, to: 'Britanny') # => true
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                  ##
         | 
| 144 | 
            +
                  # :method: *_changed?
         | 
| 145 | 
            +
                  #
         | 
| 146 | 
            +
                  # This method is generated for each attribute.
         | 
| 147 | 
            +
                  #
         | 
| 148 | 
            +
                  # Returns true if the attribute has unsaved changes.
         | 
| 149 | 
            +
                  #
         | 
| 150 | 
            +
                  #   person = Person.new
         | 
| 151 | 
            +
                  #   person.name = 'Andrew'
         | 
| 152 | 
            +
                  #   person.name_changed? # => true
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                  ##
         | 
| 155 | 
            +
                  # :method: *_change
         | 
| 156 | 
            +
                  #
         | 
| 157 | 
            +
                  # This method is generated for each attribute.
         | 
| 158 | 
            +
                  #
         | 
| 159 | 
            +
                  # Returns the old and the new value of the attribute.
         | 
| 160 | 
            +
                  #
         | 
| 161 | 
            +
                  #   person = Person.new
         | 
| 162 | 
            +
                  #   person.name = 'Nick'
         | 
| 163 | 
            +
                  #   person.name_change # => [nil, 'Nick']
         | 
| 164 | 
            +
             | 
| 165 | 
            +
                  ##
         | 
| 166 | 
            +
                  # :method: *_will_change!
         | 
| 167 | 
            +
                  #
         | 
| 168 | 
            +
                  # This method is generated for each attribute.
         | 
| 169 | 
            +
                  #
         | 
| 170 | 
            +
                  # If an attribute is modified in-place then make use of
         | 
| 171 | 
            +
                  # <tt>*_will_change!</tt> to mark that the attribute is changing.
         | 
| 172 | 
            +
                  # Otherwise Active Model can’t track changes to in-place attributes. Note
         | 
| 173 | 
            +
                  # that Active Record can detect in-place modifications automatically. You
         | 
| 174 | 
            +
                  # do not need to call <tt>*_will_change!</tt> on Active Record
         | 
| 175 | 
            +
                  # models.
         | 
| 176 | 
            +
                  #
         | 
| 177 | 
            +
                  #   person = Person.new('Sandy')
         | 
| 178 | 
            +
                  #   person.name_will_change!
         | 
| 179 | 
            +
                  #   person.name_change # => ['Sandy', 'Sandy']
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                  ##
         | 
| 182 | 
            +
                  # :method: *_was
         | 
| 183 | 
            +
                  #
         | 
| 184 | 
            +
                  # This method is generated for each attribute.
         | 
| 185 | 
            +
                  #
         | 
| 186 | 
            +
                  # Returns the old value of the attribute.
         | 
| 187 | 
            +
                  #
         | 
| 188 | 
            +
                  #   person = Person.new(name: 'Steph')
         | 
| 189 | 
            +
                  #   person.name = 'Stephanie'
         | 
| 190 | 
            +
                  #   person.name_change # => ['Steph', 'Stephanie']
         | 
| 191 | 
            +
             | 
| 192 | 
            +
                  ##
         | 
| 193 | 
            +
                  # :method: *_previous_change
         | 
| 194 | 
            +
                  #
         | 
| 195 | 
            +
                  # This method is generated for each attribute.
         | 
| 196 | 
            +
                  #
         | 
| 197 | 
            +
                  # Returns the old and the new value of the attribute before the last save.
         | 
| 198 | 
            +
                  #
         | 
| 199 | 
            +
                  #   person = Person.new
         | 
| 200 | 
            +
                  #   person.name = 'Emmanuel'
         | 
| 201 | 
            +
                  #   person.save
         | 
| 202 | 
            +
                  #   person.name_previous_change # => [nil, 'Emmanuel']
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                  ##
         | 
| 205 | 
            +
                  # :method: *_previously_was
         | 
| 206 | 
            +
                  #
         | 
| 207 | 
            +
                  # This method is generated for each attribute.
         | 
| 208 | 
            +
                  #
         | 
| 209 | 
            +
                  # Returns the old value of the attribute before the last save.
         | 
| 210 | 
            +
                  #
         | 
| 211 | 
            +
                  #   person = Person.new
         | 
| 212 | 
            +
                  #   person.name = 'Sage'
         | 
| 213 | 
            +
                  #   person.save
         | 
| 214 | 
            +
                  #   person.name_previously_was  # => nil
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                  ##
         | 
| 217 | 
            +
                  # :method: restore_*!
         | 
| 218 | 
            +
                  #
         | 
| 219 | 
            +
                  # This method is generated for each attribute.
         | 
| 220 | 
            +
                  #
         | 
| 221 | 
            +
                  # Restores the attribute to the old value.
         | 
| 222 | 
            +
                  #
         | 
| 223 | 
            +
                  #   person = Person.new
         | 
| 224 | 
            +
                  #   person.name = 'Amanda'
         | 
| 225 | 
            +
                  #   person.restore_name!
         | 
| 226 | 
            +
                  #   person.name # => nil
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                  ##
         | 
| 229 | 
            +
                  # :method: clear_*_change
         | 
| 230 | 
            +
                  #
         | 
| 231 | 
            +
                  # This method is generated for each attribute.
         | 
| 232 | 
            +
                  #
         | 
| 233 | 
            +
                  # Clears all dirty data of the attribute: current changes and previous changes.
         | 
| 234 | 
            +
                  #
         | 
| 235 | 
            +
                  #   person = Person.new(name: 'Chris')
         | 
| 236 | 
            +
                  #   person.name = 'Jason'
         | 
| 237 | 
            +
                  #   person.name_change # => ['Chris', 'Jason']
         | 
| 238 | 
            +
                  #   person.clear_name_change
         | 
| 239 | 
            +
                  #   person.name_change # => nil
         | 
| 240 | 
            +
             | 
| 126 241 | 
             
                  attribute_method_suffix "_previously_changed?", "_changed?", parameters: "**options"
         | 
| 127 242 | 
             
                  attribute_method_suffix "_change", "_will_change!", "_was", parameters: false
         | 
| 128 243 | 
             
                  attribute_method_suffix "_previous_change", "_previously_was", parameters: false
         | 
| @@ -174,23 +289,23 @@ module ActiveModel | |
| 174 289 | 
             
                  mutations_from_database.changed_attribute_names
         | 
| 175 290 | 
             
                end
         | 
| 176 291 |  | 
| 177 | 
            -
                # Dispatch target for  | 
| 178 | 
            -
                def attribute_changed?(attr_name, **options) | 
| 292 | 
            +
                # Dispatch target for {*_changed}[rdoc-label:method-i-2A_changed-3F] attribute methods.
         | 
| 293 | 
            +
                def attribute_changed?(attr_name, **options)
         | 
| 179 294 | 
             
                  mutations_from_database.changed?(attr_name.to_s, **options)
         | 
| 180 295 | 
             
                end
         | 
| 181 296 |  | 
| 182 | 
            -
                # Dispatch target for  | 
| 183 | 
            -
                def attribute_was(attr_name) | 
| 297 | 
            +
                # Dispatch target for {*_was}[rdoc-label:method-i-2A_was] attribute methods.
         | 
| 298 | 
            +
                def attribute_was(attr_name)
         | 
| 184 299 | 
             
                  mutations_from_database.original_value(attr_name.to_s)
         | 
| 185 300 | 
             
                end
         | 
| 186 301 |  | 
| 187 | 
            -
                # Dispatch target for  | 
| 188 | 
            -
                def attribute_previously_changed?(attr_name, **options) | 
| 302 | 
            +
                # Dispatch target for {*_previously_changed}[rdoc-label:method-i-2A_previously_changed-3F] attribute methods.
         | 
| 303 | 
            +
                def attribute_previously_changed?(attr_name, **options)
         | 
| 189 304 | 
             
                  mutations_before_last_save.changed?(attr_name.to_s, **options)
         | 
| 190 305 | 
             
                end
         | 
| 191 306 |  | 
| 192 | 
            -
                # Dispatch target for  | 
| 193 | 
            -
                def attribute_previously_was(attr_name) | 
| 307 | 
            +
                # Dispatch target for {*_previously_was}[rdoc-label:method-i-2A_previously_was] attribute methods.
         | 
| 308 | 
            +
                def attribute_previously_was(attr_name)
         | 
| 194 309 | 
             
                  mutations_before_last_save.original_value(attr_name.to_s)
         | 
| 195 310 | 
             
                end
         | 
| 196 311 |  | 
| @@ -247,6 +362,12 @@ module ActiveModel | |
| 247 362 | 
             
                end
         | 
| 248 363 |  | 
| 249 364 | 
             
                private
         | 
| 365 | 
            +
                  def init_internals
         | 
| 366 | 
            +
                    super
         | 
| 367 | 
            +
                    @mutations_before_last_save = nil
         | 
| 368 | 
            +
                    @mutations_from_database = nil
         | 
| 369 | 
            +
                  end
         | 
| 370 | 
            +
             | 
| 250 371 | 
             
                  def clear_attribute_change(attr_name)
         | 
| 251 372 | 
             
                    mutations_from_database.forget_change(attr_name.to_s)
         | 
| 252 373 | 
             
                  end
         | 
    
        data/lib/active_model/error.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ | |
| 3 3 | 
             
            require "active_support/core_ext/class/attribute"
         | 
| 4 4 |  | 
| 5 5 | 
             
            module ActiveModel
         | 
| 6 | 
            -
              #  | 
| 6 | 
            +
              # = Active \Model \Error
         | 
| 7 7 | 
             
              #
         | 
| 8 8 | 
             
              # Represents one single error
         | 
| 9 9 | 
             
              class Error
         | 
| @@ -121,9 +121,10 @@ module ActiveModel | |
| 121 121 | 
             
                attr_reader :attribute
         | 
| 122 122 | 
             
                # The type of error, defaults to +:invalid+ unless specified
         | 
| 123 123 | 
             
                attr_reader :type
         | 
| 124 | 
            -
                # The raw value provided as the second parameter when calling | 
| 124 | 
            +
                # The raw value provided as the second parameter when calling
         | 
| 125 | 
            +
                # <tt>errors#add</tt>
         | 
| 125 126 | 
             
                attr_reader :raw_type
         | 
| 126 | 
            -
                # The options provided when calling  | 
| 127 | 
            +
                # The options provided when calling <tt>errors#add</tt>
         | 
| 127 128 | 
             
                attr_reader :options
         | 
| 128 129 |  | 
| 129 130 | 
             
                # Returns the error message.
         | 
    
        data/lib/active_model/errors.rb
    CHANGED
    
    | @@ -3,13 +3,12 @@ | |
| 3 3 | 
             
            require "active_support/core_ext/array/conversions"
         | 
| 4 4 | 
             
            require "active_support/core_ext/string/inflections"
         | 
| 5 5 | 
             
            require "active_support/core_ext/object/deep_dup"
         | 
| 6 | 
            -
            require "active_support/core_ext/string/filters"
         | 
| 7 6 | 
             
            require "active_model/error"
         | 
| 8 7 | 
             
            require "active_model/nested_error"
         | 
| 9 8 | 
             
            require "forwardable"
         | 
| 10 9 |  | 
| 11 10 | 
             
            module ActiveModel
         | 
| 12 | 
            -
              #  | 
| 11 | 
            +
              # = Active \Model \Errors
         | 
| 13 12 | 
             
              #
         | 
| 14 13 | 
             
              # Provides error related functionalities you can include in your object
         | 
| 15 14 | 
             
              # for handling error messages and interacting with Action View helpers.
         | 
| @@ -215,7 +214,7 @@ module ActiveModel | |
| 215 214 |  | 
| 216 215 | 
             
                # Returns a Hash that can be used as the JSON representation for this
         | 
| 217 216 | 
             
                # object. You can pass the <tt>:full_messages</tt> option. This determines
         | 
| 218 | 
            -
                # if the  | 
| 217 | 
            +
                # if the JSON object should contain full messages or not (false by default).
         | 
| 219 218 | 
             
                #
         | 
| 220 219 | 
             
                #   person.errors.as_json                      # => {:name=>["cannot be nil"]}
         | 
| 221 220 | 
             
                #   person.errors.as_json(full_messages: true) # => {:name=>["name cannot be nil"]}
         | 
| @@ -285,9 +284,9 @@ module ActiveModel | |
| 285 284 | 
             
                #
         | 
| 286 285 | 
             
                #   person.errors.add(:name, :blank)
         | 
| 287 286 | 
             
                #   person.errors.messages
         | 
| 288 | 
            -
                #   # => {:name=>["can | 
| 287 | 
            +
                #   # => {:name=>["can’t be blank"]}
         | 
| 289 288 | 
             
                #
         | 
| 290 | 
            -
                #   person.errors.add(:name, :too_long,  | 
| 289 | 
            +
                #   person.errors.add(:name, :too_long, count: 25)
         | 
| 291 290 | 
             
                #   person.errors.messages
         | 
| 292 291 | 
             
                #   # => ["is too long (maximum is 25 characters)"]
         | 
| 293 292 | 
             
                #
         | 
| @@ -333,12 +332,12 @@ module ActiveModel | |
| 333 332 | 
             
                #
         | 
| 334 333 | 
             
                #   person.errors.add :name, :blank
         | 
| 335 334 | 
             
                #   person.errors.added? :name, :blank           # => true
         | 
| 336 | 
            -
                #   person.errors.added? :name, "can | 
| 335 | 
            +
                #   person.errors.added? :name, "can’t be blank" # => true
         | 
| 337 336 | 
             
                #
         | 
| 338 337 | 
             
                # If the error requires options, then it returns +true+ with
         | 
| 339 338 | 
             
                # the correct options, or +false+ with incorrect or missing options.
         | 
| 340 339 | 
             
                #
         | 
| 341 | 
            -
                #   person.errors.add :name, :too_long,  | 
| 340 | 
            +
                #   person.errors.add :name, :too_long, count: 25
         | 
| 342 341 | 
             
                #   person.errors.added? :name, :too_long, count: 25                     # => true
         | 
| 343 342 | 
             
                #   person.errors.added? :name, "is too long (maximum is 25 characters)" # => true
         | 
| 344 343 | 
             
                #   person.errors.added? :name, :too_long, count: 24                     # => false
         | 
| @@ -360,7 +359,7 @@ module ActiveModel | |
| 360 359 | 
             
                # present, or +false+ otherwise. +type+ is treated the same as for +add+.
         | 
| 361 360 | 
             
                #
         | 
| 362 361 | 
             
                #   person.errors.add :age
         | 
| 363 | 
            -
                #   person.errors.add :name, :too_long,  | 
| 362 | 
            +
                #   person.errors.add :name, :too_long, count: 25
         | 
| 364 363 | 
             
                #   person.errors.of_kind? :age                                            # => true
         | 
| 365 364 | 
             
                #   person.errors.of_kind? :name                                           # => false
         | 
| 366 365 | 
             
                #   person.errors.of_kind? :name, :too_long                                # => true
         | 
| @@ -386,7 +385,7 @@ module ActiveModel | |
| 386 385 | 
             
                #
         | 
| 387 386 | 
             
                #   person = Person.create(address: '123 First St.')
         | 
| 388 387 | 
             
                #   person.errors.full_messages
         | 
| 389 | 
            -
                #   # => ["Name is too short (minimum is 5 characters)", "Name can | 
| 388 | 
            +
                #   # => ["Name is too short (minimum is 5 characters)", "Name can’t be blank", "Email can’t be blank"]
         | 
| 390 389 | 
             
                def full_messages
         | 
| 391 390 | 
             
                  @errors.map(&:full_message)
         | 
| 392 391 | 
             
                end
         | 
| @@ -401,7 +400,7 @@ module ActiveModel | |
| 401 400 | 
             
                #
         | 
| 402 401 | 
             
                #   person = Person.create()
         | 
| 403 402 | 
             
                #   person.errors.full_messages_for(:name)
         | 
| 404 | 
            -
                #   # => ["Name is too short (minimum is 5 characters)", "Name can | 
| 403 | 
            +
                #   # => ["Name is too short (minimum is 5 characters)", "Name can’t be blank"]
         | 
| 405 404 | 
             
                def full_messages_for(attribute)
         | 
| 406 405 | 
             
                  where(attribute).map(&:full_message).freeze
         | 
| 407 406 | 
             
                end
         | 
| @@ -415,7 +414,7 @@ module ActiveModel | |
| 415 414 | 
             
                #
         | 
| 416 415 | 
             
                #   person = Person.create()
         | 
| 417 416 | 
             
                #   person.errors.messages_for(:name)
         | 
| 418 | 
            -
                #   # => ["is too short (minimum is 5 characters)", "can | 
| 417 | 
            +
                #   # => ["is too short (minimum is 5 characters)", "can’t be blank"]
         | 
| 419 418 | 
             
                def messages_for(attribute)
         | 
| 420 419 | 
             
                  where(attribute).map(&:message)
         | 
| 421 420 | 
             
                end
         | 
| @@ -472,6 +471,8 @@ module ActiveModel | |
| 472 471 | 
             
                  end
         | 
| 473 472 | 
             
              end
         | 
| 474 473 |  | 
| 474 | 
            +
              # = Active \Model \StrictValidationFailed
         | 
| 475 | 
            +
              #
         | 
| 475 476 | 
             
              # Raised when a validation cannot be corrected by end users and are considered
         | 
| 476 477 | 
             
              # exceptional.
         | 
| 477 478 | 
             
              #
         | 
| @@ -486,14 +487,18 @@ module ActiveModel | |
| 486 487 | 
             
              #   person = Person.new
         | 
| 487 488 | 
             
              #   person.name = nil
         | 
| 488 489 | 
             
              #   person.valid?
         | 
| 489 | 
            -
              #   # => ActiveModel::StrictValidationFailed: Name can | 
| 490 | 
            +
              #   # => ActiveModel::StrictValidationFailed: Name can’t be blank
         | 
| 490 491 | 
             
              class StrictValidationFailed < StandardError
         | 
| 491 492 | 
             
              end
         | 
| 492 493 |  | 
| 494 | 
            +
              # = Active \Model \RangeError
         | 
| 495 | 
            +
              #
         | 
| 493 496 | 
             
              # Raised when attribute values are out of range.
         | 
| 494 497 | 
             
              class RangeError < ::RangeError
         | 
| 495 498 | 
             
              end
         | 
| 496 499 |  | 
| 500 | 
            +
              # = Active \Model \UnknownAttributeError
         | 
| 501 | 
            +
              #
         | 
| 497 502 | 
             
              # Raised when unknown attributes are supplied via mass assignment.
         | 
| 498 503 | 
             
              #
         | 
| 499 504 | 
             
              #   class Person
         | 
| @@ -1,16 +1,16 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module ActiveModel
         | 
| 4 | 
            -
              # Returns the currently loaded version of \Active \Model as a  | 
| 4 | 
            +
              # Returns the currently loaded version of \Active \Model as a +Gem::Version+.
         | 
| 5 5 | 
             
              def self.gem_version
         | 
| 6 6 | 
             
                Gem::Version.new VERSION::STRING
         | 
| 7 7 | 
             
              end
         | 
| 8 8 |  | 
| 9 9 | 
             
              module VERSION
         | 
| 10 10 | 
             
                MAJOR = 7
         | 
| 11 | 
            -
                MINOR =  | 
| 12 | 
            -
                TINY  =  | 
| 13 | 
            -
                PRE   = " | 
| 11 | 
            +
                MINOR = 1
         | 
| 12 | 
            +
                TINY  = 0
         | 
| 13 | 
            +
                PRE   = "beta1"
         | 
| 14 14 |  | 
| 15 15 | 
             
                STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
         | 
| 16 16 | 
             
              end
         | 
    
        data/lib/active_model/lint.rb
    CHANGED
    
    | @@ -5,7 +5,7 @@ module ActiveModel | |
| 5 5 | 
             
                # == Active \Model \Lint \Tests
         | 
| 6 6 | 
             
                #
         | 
| 7 7 | 
             
                # You can test whether an object is compliant with the Active \Model API by
         | 
| 8 | 
            -
                # including  | 
| 8 | 
            +
                # including +ActiveModel::Lint::Tests+ in your TestCase. It will
         | 
| 9 9 | 
             
                # include tests that tell you whether your object is fully compliant,
         | 
| 10 10 | 
             
                # or if not, which aspects of the API are not implemented.
         | 
| 11 11 | 
             
                #
         | 
| @@ -10,14 +10,15 @@ en: | |
| 10 10 | 
             
                  inclusion: "is not included in the list"
         | 
| 11 11 | 
             
                  exclusion: "is reserved"
         | 
| 12 12 | 
             
                  invalid: "is invalid"
         | 
| 13 | 
            -
                  confirmation: "doesn | 
| 13 | 
            +
                  confirmation: "doesn’t match %{attribute}"
         | 
| 14 14 | 
             
                  accepted: "must be accepted"
         | 
| 15 | 
            -
                  empty: "can | 
| 16 | 
            -
                  blank: "can | 
| 15 | 
            +
                  empty: "can’t be empty"
         | 
| 16 | 
            +
                  blank: "can’t be blank"
         | 
| 17 17 | 
             
                  present: "must be blank"
         | 
| 18 18 | 
             
                  too_long:
         | 
| 19 19 | 
             
                    one: "is too long (maximum is 1 character)"
         | 
| 20 20 | 
             
                    other: "is too long (maximum is %{count} characters)"
         | 
| 21 | 
            +
                  password_too_long: "is too long"
         | 
| 21 22 | 
             
                  too_short:
         | 
| 22 23 | 
             
                    one: "is too short (minimum is 1 character)"
         | 
| 23 24 | 
             
                    other: "is too short (minimum is %{count} characters)"
         | 
    
        data/lib/active_model/model.rb
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            module ActiveModel
         | 
| 4 | 
            -
              #  | 
| 4 | 
            +
              # = Active \Model \Basic \Model
         | 
| 5 5 | 
             
              #
         | 
| 6 6 | 
             
              # Allows implementing models similar to ActiveRecord::Base.
         | 
| 7 7 | 
             
              # Includes ActiveModel::API for the required interface for an
         | 
| @@ -37,10 +37,34 @@ module ActiveModel | |
| 37 37 | 
             
              #   person.omg # => true
         | 
| 38 38 | 
             
              #
         | 
| 39 39 | 
             
              # For more detailed information on other functionalities available, please
         | 
| 40 | 
            -
              # refer to the specific modules included in  | 
| 40 | 
            +
              # refer to the specific modules included in +ActiveModel::Model+
         | 
| 41 41 | 
             
              # (see below).
         | 
| 42 42 | 
             
              module Model
         | 
| 43 43 | 
             
                extend ActiveSupport::Concern
         | 
| 44 44 | 
             
                include ActiveModel::API
         | 
| 45 | 
            +
                include ActiveModel::Access
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                ##
         | 
| 48 | 
            +
                # :method: slice
         | 
| 49 | 
            +
                #
         | 
| 50 | 
            +
                # :call-seq: slice(*methods)
         | 
| 51 | 
            +
                #
         | 
| 52 | 
            +
                # Returns a hash of the given methods with their names as keys and returned
         | 
| 53 | 
            +
                # values as values.
         | 
| 54 | 
            +
                #
         | 
| 55 | 
            +
                #--
         | 
| 56 | 
            +
                # Implemented by ActiveModel::Access#slice.
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                ##
         | 
| 59 | 
            +
                # :method: values_at
         | 
| 60 | 
            +
                #
         | 
| 61 | 
            +
                # :call-seq: values_at(*methods)
         | 
| 62 | 
            +
                #
         | 
| 63 | 
            +
                # Returns an array of the values returned by the given methods.
         | 
| 64 | 
            +
                #
         | 
| 65 | 
            +
                #--
         | 
| 66 | 
            +
                # Implemented by ActiveModel::Access#values_at.
         | 
| 45 67 | 
             
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              ActiveSupport.run_load_hooks(:active_model, Model)
         | 
| 46 70 | 
             
            end
         | 
    
        data/lib/active_model/naming.rb
    CHANGED
    
    | @@ -195,18 +195,15 @@ module ActiveModel | |
| 195 195 | 
             
                #
         | 
| 196 196 | 
             
                # Specify +options+ with additional translating options.
         | 
| 197 197 | 
             
                def human(options = {})
         | 
| 198 | 
            -
                  return @human  | 
| 199 | 
            -
                                       @klass.respond_to?(:i18n_scope)
         | 
| 200 | 
            -
             | 
| 201 | 
            -
                  defaults = @klass.lookup_ancestors.map do |klass|
         | 
| 202 | 
            -
                    klass.model_name.i18n_key
         | 
| 203 | 
            -
                  end
         | 
| 198 | 
            +
                  return @human if i18n_keys.empty? || i18n_scope.empty?
         | 
| 204 199 |  | 
| 200 | 
            +
                  key, *defaults = i18n_keys
         | 
| 205 201 | 
             
                  defaults << options[:default] if options[:default]
         | 
| 206 | 
            -
                  defaults <<  | 
| 202 | 
            +
                  defaults << MISSING_TRANSLATION
         | 
| 207 203 |  | 
| 208 | 
            -
                   | 
| 209 | 
            -
                   | 
| 204 | 
            +
                  translation = I18n.translate(key, scope: i18n_scope, count: 1, **options, default: defaults)
         | 
| 205 | 
            +
                  translation = @human if translation == MISSING_TRANSLATION
         | 
| 206 | 
            +
                  translation
         | 
| 210 207 | 
             
                end
         | 
| 211 208 |  | 
| 212 209 | 
             
                def uncountable?
         | 
| @@ -214,12 +211,26 @@ module ActiveModel | |
| 214 211 | 
             
                end
         | 
| 215 212 |  | 
| 216 213 | 
             
                private
         | 
| 214 | 
            +
                  MISSING_TRANSLATION = -(2**60) # :nodoc:
         | 
| 215 | 
            +
             | 
| 217 216 | 
             
                  def _singularize(string)
         | 
| 218 217 | 
             
                    ActiveSupport::Inflector.underscore(string).tr("/", "_")
         | 
| 219 218 | 
             
                  end
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                  def i18n_keys
         | 
| 221 | 
            +
                    @i18n_keys ||= if @klass.respond_to?(:lookup_ancestors)
         | 
| 222 | 
            +
                      @klass.lookup_ancestors.map { |klass| klass.model_name.i18n_key }
         | 
| 223 | 
            +
                    else
         | 
| 224 | 
            +
                      []
         | 
| 225 | 
            +
                    end
         | 
| 226 | 
            +
                  end
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                  def i18n_scope
         | 
| 229 | 
            +
                    @i18n_scope ||= @klass.respond_to?(:i18n_scope) ? [@klass.i18n_scope, :models] : []
         | 
| 230 | 
            +
                  end
         | 
| 220 231 | 
             
              end
         | 
| 221 232 |  | 
| 222 | 
            -
              #  | 
| 233 | 
            +
              # = Active \Model \Naming
         | 
| 223 234 | 
             
              #
         | 
| 224 235 | 
             
              # Creates a +model_name+ method on your object.
         | 
| 225 236 | 
             
              #
         | 
| @@ -336,5 +347,13 @@ module ActiveModel | |
| 336 347 | 
             
                  end
         | 
| 337 348 | 
             
                end
         | 
| 338 349 | 
             
                private_class_method :model_name_from_record_or_class
         | 
| 350 | 
            +
             | 
| 351 | 
            +
                private
         | 
| 352 | 
            +
                  def inherited(base)
         | 
| 353 | 
            +
                    super
         | 
| 354 | 
            +
                    base.class_eval do
         | 
| 355 | 
            +
                      @_model_name = nil
         | 
| 356 | 
            +
                    end
         | 
| 357 | 
            +
                  end
         | 
| 339 358 | 
             
              end
         | 
| 340 359 | 
             
            end
         | 
    
        data/lib/active_model/railtie.rb
    CHANGED
    
    | @@ -9,6 +9,10 @@ module ActiveModel | |
| 9 9 |  | 
| 10 10 | 
             
                config.active_model = ActiveSupport::OrderedOptions.new
         | 
| 11 11 |  | 
| 12 | 
            +
                initializer "active_model.deprecator", before: :load_environment_config do |app|
         | 
| 13 | 
            +
                  app.deprecators[:active_model] = ActiveModel.deprecator
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 12 16 | 
             
                initializer "active_model.secure_password" do
         | 
| 13 17 | 
             
                  ActiveModel::SecurePassword.min_cost = Rails.env.test?
         | 
| 14 18 | 
             
                end
         |