activerecord 7.2.2.2 → 7.2.3
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 +316 -7
- data/README.rdoc +1 -1
- data/lib/active_record/associations/alias_tracker.rb +6 -4
- data/lib/active_record/associations/belongs_to_association.rb +18 -2
- data/lib/active_record/associations/collection_association.rb +9 -7
- data/lib/active_record/associations/join_dependency/join_association.rb +25 -27
- data/lib/active_record/attribute_methods/serialization.rb +1 -1
- data/lib/active_record/attribute_methods.rb +24 -19
- data/lib/active_record/attributes.rb +37 -26
- data/lib/active_record/autosave_association.rb +22 -12
- data/lib/active_record/base.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +49 -32
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +17 -6
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +5 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +3 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +32 -3
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/quoting.rb +7 -1
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +3 -3
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -1
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +14 -12
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +8 -3
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +13 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +10 -5
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -1
- data/lib/active_record/connection_handling.rb +12 -8
- data/lib/active_record/core.rb +27 -7
- data/lib/active_record/counter_cache.rb +1 -1
- data/lib/active_record/database_configurations/connection_url_resolver.rb +3 -1
- data/lib/active_record/delegated_type.rb +18 -18
- data/lib/active_record/encryption/encryptable_record.rb +1 -1
- data/lib/active_record/encryption/encrypted_attribute_type.rb +1 -1
- data/lib/active_record/encryption/encryptor.rb +21 -20
- data/lib/active_record/enum.rb +13 -12
- data/lib/active_record/errors.rb +3 -3
- data/lib/active_record/fixture_set/table_row.rb +19 -2
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/migration.rb +2 -1
- data/lib/active_record/query_logs.rb +4 -0
- data/lib/active_record/querying.rb +4 -4
- data/lib/active_record/railtie.rb +2 -2
- data/lib/active_record/railties/databases.rake +2 -1
- data/lib/active_record/relation/calculations.rb +35 -30
- data/lib/active_record/relation/finder_methods.rb +10 -10
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +2 -0
- data/lib/active_record/relation/query_attribute.rb +1 -1
- data/lib/active_record/relation/query_methods.rb +16 -9
- data/lib/active_record/relation/where_clause.rb +8 -2
- data/lib/active_record/relation.rb +15 -5
- data/lib/active_record/schema_dumper.rb +29 -11
- data/lib/active_record/secure_token.rb +3 -3
- data/lib/active_record/signed_id.rb +7 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +7 -0
- data/lib/active_record/transactions.rb +3 -1
- data/lib/active_record.rb +1 -1
- data/lib/arel/collectors/bind.rb +1 -1
- data/lib/arel/crud.rb +2 -0
- data/lib/arel/delete_manager.rb +5 -0
- data/lib/arel/nodes/delete_statement.rb +4 -2
- data/lib/arel/nodes/update_statement.rb +4 -2
- data/lib/arel/select_manager.rb +6 -2
- data/lib/arel/update_manager.rb +5 -0
- data/lib/arel/visitors/dot.rb +2 -0
- data/lib/arel/visitors/to_sql.rb +3 -1
- metadata +8 -8
| @@ -229,6 +229,8 @@ module ActiveRecord | |
| 229 229 | 
             
                    end
         | 
| 230 230 |  | 
| 231 231 | 
             
                    def defined_for?(name: nil, column: nil, **options)
         | 
| 232 | 
            +
                      options = options.slice(*self.options.keys)
         | 
| 233 | 
            +
             | 
| 232 234 | 
             
                      (name.nil? || self.name == name.to_s) &&
         | 
| 233 235 | 
             
                        (column.nil? || Array(self.column) == Array(column).map(&:to_s)) &&
         | 
| 234 236 | 
             
                        options.all? { |k, v| self.options[k].to_s == v.to_s }
         | 
| @@ -302,8 +304,8 @@ module ActiveRecord | |
| 302 304 | 
             
                    #  t.exclusion_constraint("price WITH =, availability_range WITH &&", using: :gist, name: "price_check")
         | 
| 303 305 | 
             
                    #
         | 
| 304 306 | 
             
                    # See {connection.add_exclusion_constraint}[rdoc-ref:SchemaStatements#add_exclusion_constraint]
         | 
| 305 | 
            -
                    def exclusion_constraint( | 
| 306 | 
            -
                      @base.add_exclusion_constraint(name,  | 
| 307 | 
            +
                    def exclusion_constraint(...)
         | 
| 308 | 
            +
                      @base.add_exclusion_constraint(name, ...)
         | 
| 307 309 | 
             
                    end
         | 
| 308 310 |  | 
| 309 311 | 
             
                    # Removes the given exclusion constraint from the table.
         | 
| @@ -311,8 +313,8 @@ module ActiveRecord | |
| 311 313 | 
             
                    #  t.remove_exclusion_constraint(name: "price_check")
         | 
| 312 314 | 
             
                    #
         | 
| 313 315 | 
             
                    # See {connection.remove_exclusion_constraint}[rdoc-ref:SchemaStatements#remove_exclusion_constraint]
         | 
| 314 | 
            -
                    def remove_exclusion_constraint( | 
| 315 | 
            -
                      @base.remove_exclusion_constraint(name,  | 
| 316 | 
            +
                    def remove_exclusion_constraint(...)
         | 
| 317 | 
            +
                      @base.remove_exclusion_constraint(name, ...)
         | 
| 316 318 | 
             
                    end
         | 
| 317 319 |  | 
| 318 320 | 
             
                    # Adds a unique constraint.
         | 
| @@ -320,8 +322,8 @@ module ActiveRecord | |
| 320 322 | 
             
                    #  t.unique_constraint(:position, name: 'unique_position', deferrable: :deferred)
         | 
| 321 323 | 
             
                    #
         | 
| 322 324 | 
             
                    # See {connection.add_unique_constraint}[rdoc-ref:SchemaStatements#add_unique_constraint]
         | 
| 323 | 
            -
                    def unique_constraint( | 
| 324 | 
            -
                      @base.add_unique_constraint(name,  | 
| 325 | 
            +
                    def unique_constraint(...)
         | 
| 326 | 
            +
                      @base.add_unique_constraint(name, ...)
         | 
| 325 327 | 
             
                    end
         | 
| 326 328 |  | 
| 327 329 | 
             
                    # Removes the given unique constraint from the table.
         | 
| @@ -329,8 +331,8 @@ module ActiveRecord | |
| 329 331 | 
             
                    #  t.remove_unique_constraint(name: "unique_position")
         | 
| 330 332 | 
             
                    #
         | 
| 331 333 | 
             
                    # See {connection.remove_unique_constraint}[rdoc-ref:SchemaStatements#remove_unique_constraint]
         | 
| 332 | 
            -
                    def remove_unique_constraint( | 
| 333 | 
            -
                      @base.remove_unique_constraint(name,  | 
| 334 | 
            +
                    def remove_unique_constraint(...)
         | 
| 335 | 
            +
                      @base.remove_unique_constraint(name, ...)
         | 
| 334 336 | 
             
                    end
         | 
| 335 337 |  | 
| 336 338 | 
             
                    # Validates the given constraint on the table.
         | 
| @@ -339,8 +341,8 @@ module ActiveRecord | |
| 339 341 | 
             
                    #  t.validate_constraint "price_check"
         | 
| 340 342 | 
             
                    #
         | 
| 341 343 | 
             
                    # See {connection.validate_constraint}[rdoc-ref:SchemaStatements#validate_constraint]
         | 
| 342 | 
            -
                    def validate_constraint( | 
| 343 | 
            -
                      @base.validate_constraint(name,  | 
| 344 | 
            +
                    def validate_constraint(...)
         | 
| 345 | 
            +
                      @base.validate_constraint(name, ...)
         | 
| 344 346 | 
             
                    end
         | 
| 345 347 |  | 
| 346 348 | 
             
                    # Validates the given check constraint on the table
         | 
| @@ -349,8 +351,8 @@ module ActiveRecord | |
| 349 351 | 
             
                    #  t.validate_check_constraint name: "price_check"
         | 
| 350 352 | 
             
                    #
         | 
| 351 353 | 
             
                    # See {connection.validate_check_constraint}[rdoc-ref:SchemaStatements#validate_check_constraint]
         | 
| 352 | 
            -
                    def validate_check_constraint( | 
| 353 | 
            -
                      @base.validate_check_constraint(name,  | 
| 354 | 
            +
                    def validate_check_constraint(...)
         | 
| 355 | 
            +
                      @base.validate_check_constraint(name, ...)
         | 
| 354 356 | 
             
                    end
         | 
| 355 357 | 
             
                  end
         | 
| 356 358 |  | 
| @@ -22,7 +22,7 @@ module ActiveRecord | |
| 22 22 | 
             
                          stream.puts "  # Custom types defined in this database."
         | 
| 23 23 | 
             
                          stream.puts "  # Note that some types may not work with other database engines. Be careful if changing database."
         | 
| 24 24 | 
             
                          types.sort.each do |name, values|
         | 
| 25 | 
            -
                            stream.puts "  create_enum #{name.inspect}, #{values. | 
| 25 | 
            +
                            stream.puts "  create_enum #{name.inspect}, #{values.inspect}"
         | 
| 26 26 | 
             
                          end
         | 
| 27 27 | 
             
                          stream.puts
         | 
| 28 28 | 
             
                        end
         | 
| @@ -879,7 +879,7 @@ module ActiveRecord | |
| 879 879 | 
             
                    #
         | 
| 880 880 | 
             
                    #   validate_check_constraint :products, name: "price_check"
         | 
| 881 881 | 
             
                    #
         | 
| 882 | 
            -
                    # The +options+ hash accepts the same keys as add_check_constraint[rdoc-ref:ConnectionAdapters::SchemaStatements#add_check_constraint].
         | 
| 882 | 
            +
                    # The +options+ hash accepts the same keys as {add_check_constraint}[rdoc-ref:ConnectionAdapters::SchemaStatements#add_check_constraint].
         | 
| 883 883 | 
             
                    def validate_check_constraint(table_name, **options)
         | 
| 884 884 | 
             
                      chk_name_to_validate = check_constraint_for!(table_name, **options).name
         | 
| 885 885 |  | 
| @@ -25,7 +25,7 @@ module ActiveRecord | |
| 25 25 | 
             
                #
         | 
| 26 26 | 
             
                # The PostgreSQL adapter works with the native C (https://github.com/ged/ruby-pg) driver.
         | 
| 27 27 | 
             
                #
         | 
| 28 | 
            -
                # Options | 
| 28 | 
            +
                # ==== Options
         | 
| 29 29 | 
             
                #
         | 
| 30 30 | 
             
                # * <tt>:host</tt> - Defaults to a Unix-domain socket in /tmp. On machines without Unix-domain sockets,
         | 
| 31 31 | 
             
                #   the default is to connect to localhost.
         | 
| @@ -345,6 +345,7 @@ module ActiveRecord | |
| 345 345 | 
             
                    @lock.synchronize do
         | 
| 346 346 | 
             
                      return false unless @raw_connection
         | 
| 347 347 | 
             
                      @raw_connection.query ";"
         | 
| 348 | 
            +
                      verified!
         | 
| 348 349 | 
             
                    end
         | 
| 349 350 | 
             
                    true
         | 
| 350 351 | 
             
                  rescue PG::Error
         | 
| @@ -503,7 +504,7 @@ module ActiveRecord | |
| 503 504 | 
             
                        type.typname AS name,
         | 
| 504 505 | 
             
                        type.OID AS oid,
         | 
| 505 506 | 
             
                        n.nspname AS schema,
         | 
| 506 | 
            -
                         | 
| 507 | 
            +
                        array_agg(enum.enumlabel ORDER BY enum.enumsortorder) AS value
         | 
| 507 508 | 
             
                      FROM pg_enum AS enum
         | 
| 508 509 | 
             
                      JOIN pg_type AS type ON (type.oid = enum.enumtypid)
         | 
| 509 510 | 
             
                      JOIN pg_namespace n ON type.typnamespace = n.oid
         | 
| @@ -612,7 +613,11 @@ module ActiveRecord | |
| 612 613 | 
             
                  # Returns the version of the connected PostgreSQL server.
         | 
| 613 614 | 
             
                  def get_database_version # :nodoc:
         | 
| 614 615 | 
             
                    with_raw_connection do |conn|
         | 
| 615 | 
            -
                      conn.server_version
         | 
| 616 | 
            +
                      version = conn.server_version
         | 
| 617 | 
            +
                      if version == 0
         | 
| 618 | 
            +
                        raise ActiveRecord::ConnectionFailed, "Could not determine PostgreSQL version"
         | 
| 619 | 
            +
                      end
         | 
| 620 | 
            +
                      version
         | 
| 616 621 | 
             
                    end
         | 
| 617 622 | 
             
                  end
         | 
| 618 623 | 
             
                  alias :postgresql_version :database_version
         | 
| @@ -50,6 +50,19 @@ module ActiveRecord | |
| 50 50 | 
             
                      end
         | 
| 51 51 | 
             
                    end
         | 
| 52 52 |  | 
| 53 | 
            +
                    def quote(value) # :nodoc:
         | 
| 54 | 
            +
                      case value
         | 
| 55 | 
            +
                      when Numeric
         | 
| 56 | 
            +
                        if value.finite?
         | 
| 57 | 
            +
                          super
         | 
| 58 | 
            +
                        else
         | 
| 59 | 
            +
                          "'#{value}'"
         | 
| 60 | 
            +
                        end
         | 
| 61 | 
            +
                      else
         | 
| 62 | 
            +
                        super
         | 
| 63 | 
            +
                      end
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
             | 
| 53 66 | 
             
                    def quote_string(s)
         | 
| 54 67 | 
             
                      ::SQLite3::Database.quote(s)
         | 
| 55 68 | 
             
                    end
         | 
| @@ -74,6 +74,7 @@ module ActiveRecord | |
| 74 74 | 
             
                          Base.pluralize_table_names ? table.pluralize : table
         | 
| 75 75 | 
             
                        end
         | 
| 76 76 | 
             
                        table = strip_table_name_prefix_and_suffix(table)
         | 
| 77 | 
            +
                        options = options.slice(*fk.options.keys)
         | 
| 77 78 | 
             
                        fk_to_table = strip_table_name_prefix_and_suffix(fk.to_table)
         | 
| 78 79 | 
             
                        fk_to_table == table && options.all? { |k, v| fk.options[k].to_s == v.to_s }
         | 
| 79 80 | 
             
                      end || raise(ArgumentError, "Table '#{from_table}' has no foreign key for #{to_table || options}")
         | 
| @@ -21,7 +21,7 @@ module ActiveRecord | |
| 21 21 | 
             
                # The SQLite3 adapter works with the sqlite3-ruby drivers
         | 
| 22 22 | 
             
                # (available as gem from https://rubygems.org/gems/sqlite3).
         | 
| 23 23 | 
             
                #
         | 
| 24 | 
            -
                # Options | 
| 24 | 
            +
                # ==== Options
         | 
| 25 25 | 
             
                #
         | 
| 26 26 | 
             
                # * <tt>:database</tt> - Path to the database file.
         | 
| 27 27 | 
             
                class SQLite3Adapter < AbstractAdapter
         | 
| @@ -199,7 +199,12 @@ module ActiveRecord | |
| 199 199 | 
             
                    !(@raw_connection.nil? || @raw_connection.closed?)
         | 
| 200 200 | 
             
                  end
         | 
| 201 201 |  | 
| 202 | 
            -
                   | 
| 202 | 
            +
                  def active?
         | 
| 203 | 
            +
                    if connected?
         | 
| 204 | 
            +
                      verified!
         | 
| 205 | 
            +
                      true
         | 
| 206 | 
            +
                    end
         | 
| 207 | 
            +
                  end
         | 
| 203 208 |  | 
| 204 209 | 
             
                  alias :reset! :reconnect!
         | 
| 205 210 |  | 
| @@ -367,7 +372,7 @@ module ActiveRecord | |
| 367 372 | 
             
                  end
         | 
| 368 373 | 
             
                  alias :add_belongs_to :add_reference
         | 
| 369 374 |  | 
| 370 | 
            -
                  FK_REGEX = /.*FOREIGN KEY\s+\("( | 
| 375 | 
            +
                  FK_REGEX = /.*FOREIGN KEY\s+\("([^"]+)"\)\s+REFERENCES\s+"(\w+)"\s+\("(\w+)"\)/
         | 
| 371 376 | 
             
                  DEFERRABLE_REGEX = /DEFERRABLE INITIALLY (\w+)/
         | 
| 372 377 | 
             
                  def foreign_keys(table_name)
         | 
| 373 378 | 
             
                    # SQLite returns 1 row for each column of composite foreign keys.
         | 
| @@ -542,8 +547,8 @@ module ActiveRecord | |
| 542 547 | 
             
                        yield definition if block_given?
         | 
| 543 548 | 
             
                      end
         | 
| 544 549 |  | 
| 545 | 
            -
                       | 
| 546 | 
            -
                         | 
| 550 | 
            +
                      disable_referential_integrity do
         | 
| 551 | 
            +
                        transaction do
         | 
| 547 552 | 
             
                          move_table(table_name, altered_table_name, options.merge(temporary: true))
         | 
| 548 553 | 
             
                          move_table(altered_table_name, table_name, &caller)
         | 
| 549 554 | 
             
                        end
         | 
| @@ -170,9 +170,11 @@ module ActiveRecord | |
| 170 170 | 
             
                  prevent_writes = true if role == ActiveRecord.reading_role
         | 
| 171 171 |  | 
| 172 172 | 
             
                  append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: classes)
         | 
| 173 | 
            -
                   | 
| 174 | 
            -
             | 
| 175 | 
            -
                   | 
| 173 | 
            +
                  begin
         | 
| 174 | 
            +
                    yield
         | 
| 175 | 
            +
                  ensure
         | 
| 176 | 
            +
                    connected_to_stack.pop
         | 
| 177 | 
            +
                  end
         | 
| 176 178 | 
             
                end
         | 
| 177 179 |  | 
| 178 180 | 
             
                # Use a specified connection.
         | 
| @@ -373,11 +375,13 @@ module ActiveRecord | |
| 373 375 | 
             
                    prevent_writes = true if role == ActiveRecord.reading_role
         | 
| 374 376 |  | 
| 375 377 | 
             
                    append_to_connected_to_stack(role: role, shard: shard, prevent_writes: prevent_writes, klasses: [self])
         | 
| 376 | 
            -
                     | 
| 377 | 
            -
             | 
| 378 | 
            -
             | 
| 379 | 
            -
             | 
| 380 | 
            -
                     | 
| 378 | 
            +
                    begin
         | 
| 379 | 
            +
                      return_value = yield
         | 
| 380 | 
            +
                      return_value.load if return_value.is_a? ActiveRecord::Relation
         | 
| 381 | 
            +
                      return_value
         | 
| 382 | 
            +
                    ensure
         | 
| 383 | 
            +
                      self.connected_to_stack.pop
         | 
| 384 | 
            +
                    end
         | 
| 381 385 | 
             
                  end
         | 
| 382 386 |  | 
| 383 387 | 
             
                  def append_to_connected_to_stack(entry)
         | 
    
        data/lib/active_record/core.rb
    CHANGED
    
    | @@ -585,7 +585,7 @@ module ActiveRecord | |
| 585 585 | 
             
                #
         | 
| 586 586 | 
             
                #   topic = Topic.new(title: "Budget", author_name: "Jason")
         | 
| 587 587 | 
             
                #   topic.slice(:title, :author_name)
         | 
| 588 | 
            -
                #   => { "title" => "Budget", "author_name" => "Jason" }
         | 
| 588 | 
            +
                #   # => { "title" => "Budget", "author_name" => "Jason" }
         | 
| 589 589 | 
             
                #
         | 
| 590 590 | 
             
                #--
         | 
| 591 591 | 
             
                # Implemented by ActiveModel::Access#slice.
         | 
| @@ -599,7 +599,7 @@ module ActiveRecord | |
| 599 599 | 
             
                #
         | 
| 600 600 | 
             
                #   topic = Topic.new(title: "Budget", author_name: "Jason")
         | 
| 601 601 | 
             
                #   topic.values_at(:title, :author_name)
         | 
| 602 | 
            -
                #   => ["Budget", "Jason"]
         | 
| 602 | 
            +
                #   # => ["Budget", "Jason"]
         | 
| 603 603 | 
             
                #
         | 
| 604 604 | 
             
                #--
         | 
| 605 605 | 
             
                # Implemented by ActiveModel::Access#values_at.
         | 
| @@ -676,12 +676,14 @@ module ActiveRecord | |
| 676 676 | 
             
                # Sets the record to strict_loading mode. This will raise an error
         | 
| 677 677 | 
             
                # if the record tries to lazily load an association.
         | 
| 678 678 | 
             
                #
         | 
| 679 | 
            +
                # NOTE: Strict loading is disabled during validation in order to let the record validate its association.
         | 
| 680 | 
            +
                #
         | 
| 679 681 | 
             
                #   user = User.first
         | 
| 680 682 | 
             
                #   user.strict_loading! # => true
         | 
| 681 683 | 
             
                #   user.address.city
         | 
| 682 | 
            -
                #   => ActiveRecord::StrictLoadingViolationError
         | 
| 684 | 
            +
                #   # => ActiveRecord::StrictLoadingViolationError
         | 
| 683 685 | 
             
                #   user.comments.to_a
         | 
| 684 | 
            -
                #   => ActiveRecord::StrictLoadingViolationError
         | 
| 686 | 
            +
                #   # => ActiveRecord::StrictLoadingViolationError
         | 
| 685 687 | 
             
                #
         | 
| 686 688 | 
             
                # ==== Parameters
         | 
| 687 689 | 
             
                #
         | 
| @@ -701,7 +703,7 @@ module ActiveRecord | |
| 701 703 | 
             
                #   user.address.city # => "Tatooine"
         | 
| 702 704 | 
             
                #   user.comments.to_a # => [#<Comment:0x00...]
         | 
| 703 705 | 
             
                #   user.comments.first.ratings.to_a
         | 
| 704 | 
            -
                #   => ActiveRecord::StrictLoadingViolationError
         | 
| 706 | 
            +
                #   # => ActiveRecord::StrictLoadingViolationError
         | 
| 705 707 | 
             
                def strict_loading!(value = true, mode: :all)
         | 
| 706 708 | 
             
                  unless [:all, :n_plus_one_only].include?(mode)
         | 
| 707 709 | 
             
                    raise ArgumentError, "The :mode option must be one of [:all, :n_plus_one_only] but #{mode.inspect} was provided."
         | 
| @@ -723,11 +725,29 @@ module ActiveRecord | |
| 723 725 | 
             
                  @strict_loading_mode == :all
         | 
| 724 726 | 
             
                end
         | 
| 725 727 |  | 
| 726 | 
            -
                #  | 
| 728 | 
            +
                # Prevents records from being written to the database:
         | 
| 729 | 
            +
                #
         | 
| 730 | 
            +
                #   customer = Customer.new
         | 
| 731 | 
            +
                #   customer.readonly!
         | 
| 732 | 
            +
                #   customer.save # raises ActiveRecord::ReadOnlyRecord
         | 
| 727 733 | 
             
                #
         | 
| 728 734 | 
             
                #   customer = Customer.first
         | 
| 729 735 | 
             
                #   customer.readonly!
         | 
| 730 | 
            -
                #   customer. | 
| 736 | 
            +
                #   customer.update(name: 'New Name') # raises ActiveRecord::ReadOnlyRecord
         | 
| 737 | 
            +
                #
         | 
| 738 | 
            +
                # Read-only records cannot be deleted from the database either:
         | 
| 739 | 
            +
                #
         | 
| 740 | 
            +
                #   customer = Customer.first
         | 
| 741 | 
            +
                #   customer.readonly!
         | 
| 742 | 
            +
                #   customer.destroy # raises ActiveRecord::ReadOnlyRecord
         | 
| 743 | 
            +
                #
         | 
| 744 | 
            +
                # Please, note that the objects themselves are still mutable in memory:
         | 
| 745 | 
            +
                #
         | 
| 746 | 
            +
                #   customer = Customer.new
         | 
| 747 | 
            +
                #   customer.readonly!
         | 
| 748 | 
            +
                #   customer.name = 'New Name' # OK
         | 
| 749 | 
            +
                #
         | 
| 750 | 
            +
                # but you won't be able to persist the changes.
         | 
| 731 751 | 
             
                def readonly!
         | 
| 732 752 | 
             
                  @readonly = true
         | 
| 733 753 | 
             
                end
         | 
| @@ -28,7 +28,7 @@ module ActiveRecord | |
| 28 28 | 
             
                  #   # For the Post with id #1, reset the comments_count
         | 
| 29 29 | 
             
                  #   Post.reset_counters(1, :comments)
         | 
| 30 30 | 
             
                  #
         | 
| 31 | 
            -
                  #   # Like above, but also touch the  | 
| 31 | 
            +
                  #   # Like above, but also touch the updated_at and/or updated_on
         | 
| 32 32 | 
             
                  #   # attributes.
         | 
| 33 33 | 
             
                  #   Post.reset_counters(1, :comments, touch: true)
         | 
| 34 34 | 
             
                  def reset_counters(id, *counters, touch: nil)
         | 
| @@ -81,7 +81,9 @@ module ActiveRecord | |
| 81 81 |  | 
| 82 82 | 
             
                    def resolved_adapter
         | 
| 83 83 | 
             
                      adapter = uri.scheme && @uri.scheme.tr("-", "_")
         | 
| 84 | 
            -
                      adapter  | 
| 84 | 
            +
                      if adapter && ActiveRecord.protocol_adapters[adapter]
         | 
| 85 | 
            +
                        adapter = ActiveRecord.protocol_adapters[adapter]
         | 
| 86 | 
            +
                      end
         | 
| 85 87 | 
             
                      adapter
         | 
| 86 88 | 
             
                    end
         | 
| 87 89 |  | 
| @@ -181,16 +181,16 @@ module ActiveRecord | |
| 181 181 | 
             
                #     delegated_type :entryable, types: %w[ Message Comment ], dependent: :destroy
         | 
| 182 182 | 
             
                #   end
         | 
| 183 183 | 
             
                #
         | 
| 184 | 
            -
                #    | 
| 185 | 
            -
                #    | 
| 186 | 
            -
                #   Entry.messages | 
| 187 | 
            -
                #    | 
| 188 | 
            -
                #    | 
| 189 | 
            -
                #    | 
| 190 | 
            -
                #   Entry.comments | 
| 191 | 
            -
                #    | 
| 192 | 
            -
                #    | 
| 193 | 
            -
                #    | 
| 184 | 
            +
                #   @entry.entryable_class # => Message or Comment
         | 
| 185 | 
            +
                #   @entry.entryable_name  # => "message" or "comment"
         | 
| 186 | 
            +
                #   Entry.messages         # => Entry.where(entryable_type: "Message")
         | 
| 187 | 
            +
                #   @entry.message?        # => true when entryable_type == "Message"
         | 
| 188 | 
            +
                #   @entry.message         # => returns the message record, when entryable_type == "Message", otherwise nil
         | 
| 189 | 
            +
                #   @entry.message_id      # => returns entryable_id, when entryable_type == "Message", otherwise nil
         | 
| 190 | 
            +
                #   Entry.comments         # => Entry.where(entryable_type: "Comment")
         | 
| 191 | 
            +
                #   @entry.comment?        # => true when entryable_type == "Comment"
         | 
| 192 | 
            +
                #   @entry.comment         # => returns the comment record, when entryable_type == "Comment", otherwise nil
         | 
| 193 | 
            +
                #   @entry.comment_id      # => returns entryable_id, when entryable_type == "Comment", otherwise nil
         | 
| 194 194 | 
             
                #
         | 
| 195 195 | 
             
                # You can also declare namespaced types:
         | 
| 196 196 | 
             
                #
         | 
| @@ -199,25 +199,25 @@ module ActiveRecord | |
| 199 199 | 
             
                #   end
         | 
| 200 200 | 
             
                #
         | 
| 201 201 | 
             
                #   Entry.access_notice_messages
         | 
| 202 | 
            -
                #   entry.access_notice_message
         | 
| 203 | 
            -
                #   entry.access_notice_message?
         | 
| 202 | 
            +
                #   @entry.access_notice_message
         | 
| 203 | 
            +
                #   @entry.access_notice_message?
         | 
| 204 204 | 
             
                #
         | 
| 205 | 
            -
                #  | 
| 205 | 
            +
                # ==== Options
         | 
| 206 206 | 
             
                #
         | 
| 207 207 | 
             
                # The +options+ are passed directly to the +belongs_to+ call, so this is where you declare +dependent+ etc.
         | 
| 208 208 | 
             
                # The following options can be included to specialize the behavior of the delegated type convenience methods.
         | 
| 209 209 | 
             
                #
         | 
| 210 | 
            -
                # [ | 
| 210 | 
            +
                # [+:foreign_key+]
         | 
| 211 211 | 
             
                #   Specify the foreign key used for the convenience methods. By default this is guessed to be the passed
         | 
| 212 212 | 
             
                #   +role+ with an "_id" suffix. So a class that defines a
         | 
| 213 213 | 
             
                #   <tt>delegated_type :entryable, types: %w[ Message Comment ]</tt> association will use "entryable_id" as
         | 
| 214 214 | 
             
                #   the default <tt>:foreign_key</tt>.
         | 
| 215 | 
            -
                # [ | 
| 215 | 
            +
                # [+:foreign_type+]
         | 
| 216 216 | 
             
                #   Specify the column used to store the associated object's type. By default this is inferred to be the passed
         | 
| 217 217 | 
             
                #   +role+ with a "_type" suffix. A class that defines a
         | 
| 218 218 | 
             
                #   <tt>delegated_type :entryable, types: %w[ Message Comment ]</tt> association will use "entryable_type" as
         | 
| 219 219 | 
             
                #   the default <tt>:foreign_type</tt>.
         | 
| 220 | 
            -
                # [ | 
| 220 | 
            +
                # [+:primary_key+]
         | 
| 221 221 | 
             
                #   Specify the method that returns the primary key of associated object used for the convenience methods.
         | 
| 222 222 | 
             
                #   By default this is +id+.
         | 
| 223 223 | 
             
                #
         | 
| @@ -226,8 +226,8 @@ module ActiveRecord | |
| 226 226 | 
             
                #     delegated_type :entryable, types: %w[ Message Comment ], primary_key: :uuid, foreign_key: :entryable_uuid
         | 
| 227 227 | 
             
                #   end
         | 
| 228 228 | 
             
                #
         | 
| 229 | 
            -
                #    | 
| 230 | 
            -
                #    | 
| 229 | 
            +
                #   @entry.message_uuid # => returns entryable_uuid, when entryable_type == "Message", otherwise nil
         | 
| 230 | 
            +
                #   @entry.comment_uuid # => returns entryable_uuid, when entryable_type == "Comment", otherwise nil
         | 
| 231 231 | 
             
                def delegated_type(role, types:, **options)
         | 
| 232 232 | 
             
                  belongs_to role, options.delete(:scope), **options.merge(polymorphic: true)
         | 
| 233 233 | 
             
                  define_delegated_type_methods role, types: types, options: options
         | 
| @@ -16,7 +16,7 @@ module ActiveRecord | |
| 16 16 | 
             
                  class_methods do
         | 
| 17 17 | 
             
                    # Encrypts the +name+ attribute.
         | 
| 18 18 | 
             
                    #
         | 
| 19 | 
            -
                    #  | 
| 19 | 
            +
                    # ==== Options
         | 
| 20 20 | 
             
                    #
         | 
| 21 21 | 
             
                    # * <tt>:key_provider</tt> - A key provider to provide encryption and decryption keys. Defaults to
         | 
| 22 22 | 
             
                    #   +ActiveRecord::Encryption.key_provider+.
         | 
| @@ -15,7 +15,7 @@ module ActiveRecord | |
| 15 15 | 
             
                  delegate :key_provider, :downcase?, :deterministic?, :previous_schemes, :with_context, :fixed?, to: :scheme
         | 
| 16 16 | 
             
                  delegate :accessor, :type, to: :cast_type
         | 
| 17 17 |  | 
| 18 | 
            -
                  #  | 
| 18 | 
            +
                  # ==== Options
         | 
| 19 19 | 
             
                  #
         | 
| 20 20 | 
             
                  # * <tt>:scheme</tt> - A +Scheme+ with the encryption properties for this attribute.
         | 
| 21 21 | 
             
                  # * <tt>:cast_type</tt> - A type that will be used to serialize (before encrypting) and deserialize
         | 
| @@ -12,33 +12,34 @@ module ActiveRecord | |
| 12 12 | 
             
                # It interacts with a KeyProvider for getting the keys, and delegate to
         | 
| 13 13 | 
             
                # ActiveRecord::Encryption::Cipher the actual encryption algorithm.
         | 
| 14 14 | 
             
                class Encryptor
         | 
| 15 | 
            -
                  #  | 
| 15 | 
            +
                  # ==== Options
         | 
| 16 16 | 
             
                  #
         | 
| 17 | 
            -
                  #  | 
| 18 | 
            -
                  #    | 
| 17 | 
            +
                  # [+:compress+]
         | 
| 18 | 
            +
                  #   Boolean indicating whether records should be compressed before
         | 
| 19 | 
            +
                  #   encryption. Defaults to +true+.
         | 
| 19 20 | 
             
                  def initialize(compress: true)
         | 
| 20 21 | 
             
                    @compress = compress
         | 
| 21 22 | 
             
                  end
         | 
| 22 23 |  | 
| 23 | 
            -
                  # Encrypts +clean_text+ and returns the encrypted result
         | 
| 24 | 
            +
                  # Encrypts +clean_text+ and returns the encrypted result.
         | 
| 24 25 | 
             
                  #
         | 
| 25 26 | 
             
                  # Internally, it will:
         | 
| 26 27 | 
             
                  #
         | 
| 27 | 
            -
                  # 1. Create a new ActiveRecord::Encryption::Message
         | 
| 28 | 
            -
                  # 2. Compress and encrypt +clean_text+ as the message payload
         | 
| 29 | 
            -
                  # 3. Serialize it with +ActiveRecord::Encryption.message_serializer+ | 
| 30 | 
            -
                  #    by default)
         | 
| 31 | 
            -
                  # 4. Encode the result with  | 
| 28 | 
            +
                  # 1. Create a new ActiveRecord::Encryption::Message.
         | 
| 29 | 
            +
                  # 2. Compress and encrypt +clean_text+ as the message payload.
         | 
| 30 | 
            +
                  # 3. Serialize it with +ActiveRecord::Encryption.message_serializer+
         | 
| 31 | 
            +
                  #    (+ActiveRecord::Encryption::SafeMarshal+ by default).
         | 
| 32 | 
            +
                  # 4. Encode the result with Base64.
         | 
| 32 33 | 
             
                  #
         | 
| 33 | 
            -
                  #  | 
| 34 | 
            +
                  # ==== Options
         | 
| 34 35 | 
             
                  #
         | 
| 35 | 
            -
                  # [ | 
| 36 | 
            +
                  # [+:key_provider+]
         | 
| 36 37 | 
             
                  #   Key provider to use for the encryption operation. It will default to
         | 
| 37 38 | 
             
                  #   +ActiveRecord::Encryption.key_provider+ when not provided.
         | 
| 38 39 | 
             
                  #
         | 
| 39 | 
            -
                  # [ | 
| 40 | 
            +
                  # [+:cipher_options+]
         | 
| 40 41 | 
             
                  #   Cipher-specific options that will be passed to the Cipher configured in
         | 
| 41 | 
            -
                  #   +ActiveRecord::Encryption.cipher | 
| 42 | 
            +
                  #   +ActiveRecord::Encryption.cipher+.
         | 
| 42 43 | 
             
                  def encrypt(clear_text, key_provider: default_key_provider, cipher_options: {})
         | 
| 43 44 | 
             
                    clear_text = force_encoding_if_needed(clear_text) if cipher_options[:deterministic]
         | 
| 44 45 |  | 
| @@ -46,17 +47,17 @@ module ActiveRecord | |
| 46 47 | 
             
                    serialize_message build_encrypted_message(clear_text, key_provider: key_provider, cipher_options: cipher_options)
         | 
| 47 48 | 
             
                  end
         | 
| 48 49 |  | 
| 49 | 
            -
                  # Decrypts an +encrypted_text+ and returns the result as clean text
         | 
| 50 | 
            +
                  # Decrypts an +encrypted_text+ and returns the result as clean text.
         | 
| 50 51 | 
             
                  #
         | 
| 51 | 
            -
                  #  | 
| 52 | 
            +
                  # ==== Options
         | 
| 52 53 | 
             
                  #
         | 
| 53 | 
            -
                  # [ | 
| 54 | 
            +
                  # [+:key_provider+]
         | 
| 54 55 | 
             
                  #   Key provider to use for the encryption operation. It will default to
         | 
| 55 | 
            -
                  #   +ActiveRecord::Encryption.key_provider+ when not provided
         | 
| 56 | 
            +
                  #   +ActiveRecord::Encryption.key_provider+ when not provided.
         | 
| 56 57 | 
             
                  #
         | 
| 57 | 
            -
                  # [ | 
| 58 | 
            +
                  # [+:cipher_options+]
         | 
| 58 59 | 
             
                  #   Cipher-specific options that will be passed to the Cipher configured in
         | 
| 59 | 
            -
                  #   +ActiveRecord::Encryption.cipher | 
| 60 | 
            +
                  #   +ActiveRecord::Encryption.cipher+.
         | 
| 60 61 | 
             
                  def decrypt(encrypted_text, key_provider: default_key_provider, cipher_options: {})
         | 
| 61 62 | 
             
                    message = deserialize_message(encrypted_text)
         | 
| 62 63 | 
             
                    keys = key_provider.decryption_keys(message)
         | 
| @@ -66,7 +67,7 @@ module ActiveRecord | |
| 66 67 | 
             
                    raise Errors::Decryption
         | 
| 67 68 | 
             
                  end
         | 
| 68 69 |  | 
| 69 | 
            -
                  # Returns whether the text is encrypted or not
         | 
| 70 | 
            +
                  # Returns whether the text is encrypted or not.
         | 
| 70 71 | 
             
                  def encrypted?(text)
         | 
| 71 72 | 
             
                    deserialize_message(text)
         | 
| 72 73 | 
             
                    true
         | 
    
        data/lib/active_record/enum.rb
    CHANGED
    
    | @@ -119,7 +119,18 @@ module ActiveRecord | |
| 119 119 | 
             
              #     enum :status, [ :active, :archived ], instance_methods: false
         | 
| 120 120 | 
             
              #   end
         | 
| 121 121 | 
             
              #
         | 
| 122 | 
            -
              #  | 
| 122 | 
            +
              # By default, an +ArgumentError+ will be raised when assigning an invalid value:
         | 
| 123 | 
            +
              #
         | 
| 124 | 
            +
              #   class Conversation < ActiveRecord::Base
         | 
| 125 | 
            +
              #     enum :status, [ :active, :archived ]
         | 
| 126 | 
            +
              #   end
         | 
| 127 | 
            +
              #
         | 
| 128 | 
            +
              #   conversation = Conversation.new
         | 
| 129 | 
            +
              #
         | 
| 130 | 
            +
              #   conversation.status = :unknown # 'unknown' is not a valid status (ArgumentError)
         | 
| 131 | 
            +
              #
         | 
| 132 | 
            +
              # If, instead, you want the enum value to be validated before saving, use the
         | 
| 133 | 
            +
              # +:validate+ option:
         | 
| 123 134 | 
             
              #
         | 
| 124 135 | 
             
              #   class Conversation < ActiveRecord::Base
         | 
| 125 136 | 
             
              #     enum :status, [ :active, :archived ], validate: true
         | 
| @@ -136,7 +147,7 @@ module ActiveRecord | |
| 136 147 | 
             
              #   conversation.status = :active
         | 
| 137 148 | 
             
              #   conversation.valid? # => true
         | 
| 138 149 | 
             
              #
         | 
| 139 | 
            -
              #  | 
| 150 | 
            +
              # You may also pass additional validation options:
         | 
| 140 151 | 
             
              #
         | 
| 141 152 | 
             
              #   class Conversation < ActiveRecord::Base
         | 
| 142 153 | 
             
              #     enum :status, [ :active, :archived ], validate: { allow_nil: true }
         | 
| @@ -152,16 +163,6 @@ module ActiveRecord | |
| 152 163 | 
             
              #
         | 
| 153 164 | 
             
              #   conversation.status = :active
         | 
| 154 165 | 
             
              #   conversation.valid? # => true
         | 
| 155 | 
            -
              #
         | 
| 156 | 
            -
              # Otherwise +ArgumentError+ will raise:
         | 
| 157 | 
            -
              #
         | 
| 158 | 
            -
              #   class Conversation < ActiveRecord::Base
         | 
| 159 | 
            -
              #     enum :status, [ :active, :archived ]
         | 
| 160 | 
            -
              #   end
         | 
| 161 | 
            -
              #
         | 
| 162 | 
            -
              #   conversation = Conversation.new
         | 
| 163 | 
            -
              #
         | 
| 164 | 
            -
              #   conversation.status = :unknown # 'unknown' is not a valid status (ArgumentError)
         | 
| 165 166 | 
             
              module Enum
         | 
| 166 167 | 
             
                def self.extended(base) # :nodoc:
         | 
| 167 168 | 
             
                  base.class_attribute(:defined_enums, instance_writer: false, default: {})
         | 
    
        data/lib/active_record/errors.rb
    CHANGED
    
    | @@ -13,7 +13,7 @@ module ActiveRecord | |
| 13 13 |  | 
| 14 14 | 
             
              # Raised when the single-table inheritance mechanism fails to locate the subclass
         | 
| 15 15 | 
             
              # (for example due to improper usage of column that
         | 
| 16 | 
            -
              # {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema | 
| 16 | 
            +
              # {ActiveRecord::Base.inheritance_column}[rdoc-ref:ModelSchema.inheritance_column]
         | 
| 17 17 | 
             
              # points to).
         | 
| 18 18 | 
             
              class SubclassNotFound < ActiveRecordError
         | 
| 19 19 | 
             
              end
         | 
| @@ -431,7 +431,7 @@ module ActiveRecord | |
| 431 431 | 
             
              UnknownAttributeError = ActiveModel::UnknownAttributeError
         | 
| 432 432 |  | 
| 433 433 | 
             
              # Raised when an error occurred while doing a mass assignment to an attribute through the
         | 
| 434 | 
            -
              # {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=] method.
         | 
| 434 | 
            +
              # {ActiveRecord::Base#attributes=}[rdoc-ref:ActiveModel::AttributeAssignment#attributes=] method.
         | 
| 435 435 | 
             
              # The exception has an +attribute+ property that is the name of the offending attribute.
         | 
| 436 436 | 
             
              class AttributeAssignmentError < ActiveRecordError
         | 
| 437 437 | 
             
                attr_reader :exception, :attribute
         | 
| @@ -444,7 +444,7 @@ module ActiveRecord | |
| 444 444 | 
             
              end
         | 
| 445 445 |  | 
| 446 446 | 
             
              # Raised when there are multiple errors while doing a mass assignment through the
         | 
| 447 | 
            -
              # {ActiveRecord::Base#attributes=}[rdoc-ref:AttributeAssignment#attributes=]
         | 
| 447 | 
            +
              # {ActiveRecord::Base#attributes=}[rdoc-ref:ActiveModel::AttributeAssignment#attributes=]
         | 
| 448 448 | 
             
              # method. The exception has an +errors+ property that contains an array of AttributeAssignmentError
         | 
| 449 449 | 
             
              # objects, each corresponding to the error while assigning to an attribute.
         | 
| 450 450 | 
             
              class MultiparameterAssignmentErrors < ActiveRecordError
         | 
| @@ -193,8 +193,25 @@ module ActiveRecord | |
| 193 193 |  | 
| 194 194 | 
             
                        targets = targets.is_a?(Array) ? targets : targets.split(/\s*,\s*/)
         | 
| 195 195 | 
             
                        joins   = targets.map do |target|
         | 
| 196 | 
            -
                          join = { | 
| 197 | 
            -
             | 
| 196 | 
            +
                          join = {}
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                          if rhs_key.is_a?(Array)
         | 
| 199 | 
            +
                            composite_key = ActiveRecord::FixtureSet.composite_identify(target, rhs_key)
         | 
| 200 | 
            +
                            composite_key.each do |column, value|
         | 
| 201 | 
            +
                              join[column] = value
         | 
| 202 | 
            +
                            end
         | 
| 203 | 
            +
                          else
         | 
| 204 | 
            +
                            join[rhs_key] = ActiveRecord::FixtureSet.identify(target, column_type)
         | 
| 205 | 
            +
                          end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                          if lhs_key.is_a?(Array)
         | 
| 208 | 
            +
                            lhs_key.zip(model_metadata.primary_key_name).each do |fkey, pkey|
         | 
| 209 | 
            +
                              join[fkey] = @row[pkey]
         | 
| 210 | 
            +
                            end
         | 
| 211 | 
            +
                          else
         | 
| 212 | 
            +
                            join[lhs_key] = @row[model_metadata.primary_key_name]
         | 
| 213 | 
            +
                          end
         | 
| 214 | 
            +
             | 
| 198 215 | 
             
                          association.timestamp_column_names.each do |col|
         | 
| 199 216 | 
             
                            join[col] = @now
         | 
| 200 217 | 
             
                          end
         | 
| @@ -1532,7 +1532,8 @@ module ActiveRecord | |
| 1532 1532 | 
             
                    return if down? && !migrated.include?(migration.version.to_i)
         | 
| 1533 1533 | 
             
                    return if up?   &&  migrated.include?(migration.version.to_i)
         | 
| 1534 1534 |  | 
| 1535 | 
            -
                     | 
| 1535 | 
            +
                    message = up? ? "Migrating to" : "Reverting"
         | 
| 1536 | 
            +
                    Base.logger.info "#{message} #{migration.name} (#{migration.version})" if Base.logger
         | 
| 1536 1537 |  | 
| 1537 1538 | 
             
                    ddl_transaction(migration) do
         | 
| 1538 1539 | 
             
                      migration.migrate(@direction)
         | 
| @@ -28,6 +28,10 @@ module ActiveRecord | |
| 28 28 | 
             
              # * +database+
         | 
| 29 29 | 
             
              # * +source_location+
         | 
| 30 30 | 
             
              #
         | 
| 31 | 
            +
              # WARNING: Calculating the +source_location+ of a query can be slow, so you should consider its impact if using it in a production environment.
         | 
| 32 | 
            +
              #
         | 
| 33 | 
            +
              # Also see {config.active_record.verbose_query_logs}[https://guides.rubyonrails.org/debugging_rails_applications.html#verbose-query-logs].
         | 
| 34 | 
            +
              #
         | 
| 31 35 | 
             
              # Action Controller adds default tags when loaded:
         | 
| 32 36 | 
             
              #
         | 
| 33 37 | 
             
              # * +controller+
         |