activerecord 5.2.8.1 → 6.1.0
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.
Potentially problematic release.
This version of activerecord might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +849 -630
- data/MIT-LICENSE +3 -1
- data/README.rdoc +7 -5
- data/examples/performance.rb +1 -1
- data/lib/active_record/aggregations.rb +5 -4
- data/lib/active_record/association_relation.rb +22 -12
- data/lib/active_record/associations/alias_tracker.rb +19 -16
- data/lib/active_record/associations/association.rb +95 -42
- data/lib/active_record/associations/association_scope.rb +21 -21
- data/lib/active_record/associations/belongs_to_association.rb +50 -46
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -5
- data/lib/active_record/associations/builder/association.rb +23 -21
- data/lib/active_record/associations/builder/belongs_to.rb +29 -59
- data/lib/active_record/associations/builder/collection_association.rb +8 -17
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -2
- data/lib/active_record/associations/builder/has_one.rb +33 -2
- data/lib/active_record/associations/builder/singular_association.rb +3 -1
- data/lib/active_record/associations/collection_association.rb +31 -29
- data/lib/active_record/associations/collection_proxy.rb +25 -21
- data/lib/active_record/associations/foreign_association.rb +20 -0
- data/lib/active_record/associations/has_many_association.rb +26 -13
- data/lib/active_record/associations/has_many_through_association.rb +24 -18
- data/lib/active_record/associations/has_one_association.rb +43 -31
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +41 -20
- data/lib/active_record/associations/join_dependency/join_part.rb +5 -5
- data/lib/active_record/associations/join_dependency.rb +91 -60
- data/lib/active_record/associations/preloader/association.rb +71 -43
- data/lib/active_record/associations/preloader/through_association.rb +49 -40
- data/lib/active_record/associations/preloader.rb +47 -34
- data/lib/active_record/associations/singular_association.rb +3 -17
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +133 -25
- data/lib/active_record/attribute_assignment.rb +17 -19
- data/lib/active_record/attribute_methods/before_type_cast.rb +13 -7
- data/lib/active_record/attribute_methods/dirty.rb +101 -40
- data/lib/active_record/attribute_methods/primary_key.rb +20 -25
- data/lib/active_record/attribute_methods/query.rb +4 -8
- data/lib/active_record/attribute_methods/read.rb +14 -56
- data/lib/active_record/attribute_methods/serialization.rb +12 -7
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -15
- data/lib/active_record/attribute_methods/write.rb +18 -34
- data/lib/active_record/attribute_methods.rb +81 -143
- data/lib/active_record/attributes.rb +45 -8
- data/lib/active_record/autosave_association.rb +57 -42
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +2 -15
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +272 -130
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -36
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +167 -146
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -14
- data/lib/active_record/connection_adapters/abstract/quoting.rb +98 -47
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -110
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +203 -90
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +2 -4
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +381 -146
- data/lib/active_record/connection_adapters/abstract/transaction.rb +155 -68
- data/lib/active_record/connection_adapters/abstract_adapter.rb +229 -98
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +243 -275
- data/lib/active_record/connection_adapters/column.rb +30 -12
- data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +86 -32
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -2
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +34 -10
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +48 -32
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +139 -19
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +14 -9
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +53 -18
- data/lib/active_record/connection_adapters/pool_config.rb +63 -0
- data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +37 -28
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +38 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
- data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +3 -4
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +25 -7
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +15 -3
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +47 -10
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +2 -2
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +19 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +120 -100
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +31 -26
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +222 -112
- data/lib/active_record/connection_adapters/schema_cache.rb +127 -21
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +19 -6
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +144 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +77 -13
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +174 -186
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_adapters.rb +50 -0
- data/lib/active_record/connection_handling.rb +285 -33
- data/lib/active_record/core.rb +304 -106
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
- data/lib/active_record/database_configurations/database_config.rb +80 -0
- data/lib/active_record/database_configurations/hash_config.rb +96 -0
- data/lib/active_record/database_configurations/url_config.rb +53 -0
- data/lib/active_record/database_configurations.rb +272 -0
- data/lib/active_record/delegated_type.rb +209 -0
- data/lib/active_record/destroy_association_async_job.rb +36 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +71 -17
- data/lib/active_record/errors.rb +62 -19
- data/lib/active_record/explain.rb +10 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +10 -17
- data/lib/active_record/fixture_set/model_metadata.rb +32 -0
- data/lib/active_record/fixture_set/render_context.rb +17 -0
- data/lib/active_record/fixture_set/table_row.rb +152 -0
- data/lib/active_record/fixture_set/table_rows.rb +46 -0
- data/lib/active_record/fixtures.rb +197 -481
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +53 -24
- data/lib/active_record/insert_all.rb +208 -0
- data/lib/active_record/integration.rb +67 -17
- data/lib/active_record/internal_metadata.rb +26 -9
- data/lib/active_record/legacy_yaml_adapter.rb +7 -3
- data/lib/active_record/locking/optimistic.rb +26 -22
- data/lib/active_record/locking/pessimistic.rb +9 -5
- data/lib/active_record/log_subscriber.rb +34 -35
- data/lib/active_record/middleware/database_selector/resolver/session.rb +48 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +92 -0
- data/lib/active_record/middleware/database_selector.rb +77 -0
- data/lib/active_record/migration/command_recorder.rb +96 -44
- data/lib/active_record/migration/compatibility.rb +141 -64
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +205 -156
- data/lib/active_record/model_schema.rb +148 -22
- data/lib/active_record/nested_attributes.rb +4 -7
- data/lib/active_record/no_touching.rb +8 -1
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +267 -59
- data/lib/active_record/query_cache.rb +21 -4
- data/lib/active_record/querying.rb +40 -23
- data/lib/active_record/railtie.rb +113 -74
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +402 -78
- data/lib/active_record/readonly_attributes.rb +4 -0
- data/lib/active_record/reflection.rb +109 -93
- data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
- data/lib/active_record/relation/batches.rb +44 -35
- data/lib/active_record/relation/calculations.rb +153 -90
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +64 -39
- data/lib/active_record/relation/from_clause.rb +5 -1
- data/lib/active_record/relation/merger.rb +32 -40
- data/lib/active_record/relation/predicate_builder/array_handler.rb +13 -13
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +5 -9
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +4 -7
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
- data/lib/active_record/relation/predicate_builder.rb +58 -40
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +472 -186
- data/lib/active_record/relation/record_fetch_warning.rb +3 -3
- data/lib/active_record/relation/spawn_methods.rb +9 -9
- data/lib/active_record/relation/where_clause.rb +108 -58
- data/lib/active_record/relation.rb +375 -104
- data/lib/active_record/result.rb +64 -38
- data/lib/active_record/runtime_registry.rb +2 -2
- data/lib/active_record/sanitization.rb +22 -41
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +54 -9
- data/lib/active_record/schema_migration.rb +7 -9
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +17 -24
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/secure_token.rb +16 -8
- data/lib/active_record/serialization.rb +5 -3
- data/lib/active_record/signed_id.rb +116 -0
- data/lib/active_record/statement_cache.rb +49 -6
- data/lib/active_record/store.rb +88 -9
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +39 -43
- data/lib/active_record/tasks/database_tasks.rb +276 -81
- data/lib/active_record/tasks/mysql_database_tasks.rb +37 -39
- data/lib/active_record/tasks/postgresql_database_tasks.rb +27 -32
- data/lib/active_record/tasks/sqlite_database_tasks.rb +14 -17
- data/lib/active_record/test_databases.rb +24 -0
- data/lib/active_record/test_fixtures.rb +246 -0
- data/lib/active_record/timestamp.rb +43 -32
- data/lib/active_record/touch_later.rb +23 -22
- data/lib/active_record/transactions.rb +58 -116
- data/lib/active_record/translation.rb +1 -1
- data/lib/active_record/type/adapter_specific_registry.rb +3 -13
- data/lib/active_record/type/hash_lookup_type_map.rb +0 -1
- data/lib/active_record/type/serialized.rb +6 -3
- data/lib/active_record/type/time.rb +10 -0
- data/lib/active_record/type/type_map.rb +0 -1
- data/lib/active_record/type/unsigned_integer.rb +0 -1
- data/lib/active_record/type.rb +10 -5
- data/lib/active_record/type_caster/connection.rb +15 -15
- data/lib/active_record/type_caster/map.rb +8 -8
- data/lib/active_record/validations/associated.rb +1 -2
- data/lib/active_record/validations/numericality.rb +35 -0
- data/lib/active_record/validations/uniqueness.rb +38 -30
- data/lib/active_record/validations.rb +4 -3
- data/lib/active_record.rb +13 -12
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +41 -0
- data/lib/arel/collectors/bind.rb +29 -0
- data/lib/arel/collectors/composite.rb +39 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +27 -0
- data/lib/arel/collectors/substitute_binds.rb +35 -0
- data/lib/arel/crud.rb +42 -0
- data/lib/arel/delete_manager.rb +18 -0
- data/lib/arel/errors.rb +9 -0
- data/lib/arel/expressions.rb +29 -0
- data/lib/arel/factory_methods.rb +49 -0
- data/lib/arel/insert_manager.rb +49 -0
- data/lib/arel/math.rb +45 -0
- data/lib/arel/nodes/and.rb +32 -0
- data/lib/arel/nodes/ascending.rb +23 -0
- data/lib/arel/nodes/binary.rb +126 -0
- data/lib/arel/nodes/bind_param.rb +44 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +62 -0
- data/lib/arel/nodes/comment.rb +29 -0
- data/lib/arel/nodes/count.rb +12 -0
- data/lib/arel/nodes/delete_statement.rb +45 -0
- data/lib/arel/nodes/descending.rb +23 -0
- data/lib/arel/nodes/equality.rb +15 -0
- data/lib/arel/nodes/extract.rb +24 -0
- data/lib/arel/nodes/false.rb +16 -0
- data/lib/arel/nodes/full_outer_join.rb +8 -0
- data/lib/arel/nodes/function.rb +44 -0
- data/lib/arel/nodes/grouping.rb +11 -0
- data/lib/arel/nodes/homogeneous_in.rb +72 -0
- data/lib/arel/nodes/in.rb +15 -0
- data/lib/arel/nodes/infix_operation.rb +92 -0
- data/lib/arel/nodes/inner_join.rb +8 -0
- data/lib/arel/nodes/insert_statement.rb +37 -0
- data/lib/arel/nodes/join_source.rb +20 -0
- data/lib/arel/nodes/matches.rb +18 -0
- data/lib/arel/nodes/named_function.rb +23 -0
- data/lib/arel/nodes/node.rb +51 -0
- data/lib/arel/nodes/node_expression.rb +13 -0
- data/lib/arel/nodes/ordering.rb +27 -0
- data/lib/arel/nodes/outer_join.rb +8 -0
- data/lib/arel/nodes/over.rb +15 -0
- data/lib/arel/nodes/regexp.rb +16 -0
- data/lib/arel/nodes/right_outer_join.rb +8 -0
- data/lib/arel/nodes/select_core.rb +67 -0
- data/lib/arel/nodes/select_statement.rb +41 -0
- data/lib/arel/nodes/sql_literal.rb +19 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +31 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +44 -0
- data/lib/arel/nodes/unary_operation.rb +20 -0
- data/lib/arel/nodes/unqualified_column.rb +22 -0
- data/lib/arel/nodes/update_statement.rb +41 -0
- data/lib/arel/nodes/values_list.rb +9 -0
- data/lib/arel/nodes/window.rb +126 -0
- data/lib/arel/nodes/with.rb +11 -0
- data/lib/arel/nodes.rb +70 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +250 -0
- data/lib/arel/select_manager.rb +270 -0
- data/lib/arel/table.rb +118 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/dot.rb +308 -0
- data/lib/arel/visitors/mysql.rb +93 -0
- data/lib/arel/visitors/postgresql.rb +120 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +899 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors.rb +13 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +54 -0
- data/lib/rails/generators/active_record/application_record/application_record_generator.rb +0 -1
- data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +3 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +7 -5
- data/lib/rails/generators/active_record/migration.rb +19 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +120 -35
- data/lib/active_record/attribute_decorators.rb +0 -90
- data/lib/active_record/collection_cache_key.rb +0 -53
- data/lib/active_record/connection_adapters/connection_specification.rb +0 -287
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -33
- data/lib/active_record/define_callbacks.rb +0 -22
- data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -19
- data/lib/active_record/relation/where_clause_factory.rb +0 -34
| @@ -1,6 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require "mutex_m"
         | 
| 4 | 
            +
            require "active_support/core_ext/enumerable"
         | 
| 4 5 |  | 
| 5 6 | 
             
            module ActiveRecord
         | 
| 6 7 | 
             
              # = Active Record Attribute Methods
         | 
| @@ -18,25 +19,25 @@ module ActiveRecord | |
| 18 19 | 
             
                  include TimeZoneConversion
         | 
| 19 20 | 
             
                  include Dirty
         | 
| 20 21 | 
             
                  include Serialization
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                  delegate :column_for_attribute, to: :class
         | 
| 23 22 | 
             
                end
         | 
| 24 23 |  | 
| 25 | 
            -
                 | 
| 26 | 
            -
                  def self.set_name_cache(name, value)
         | 
| 27 | 
            -
                    const_name = "ATTR_#{name}"
         | 
| 28 | 
            -
                    unless const_defined? const_name
         | 
| 29 | 
            -
                      const_set const_name, value.dup.freeze
         | 
| 30 | 
            -
                    end
         | 
| 31 | 
            -
                  end
         | 
| 32 | 
            -
                }
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                BLACKLISTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
         | 
| 24 | 
            +
                RESTRICTED_CLASS_METHODS = %w(private public protected allocate new name parent superclass)
         | 
| 35 25 |  | 
| 36 26 | 
             
                class GeneratedAttributeMethods < Module #:nodoc:
         | 
| 37 27 | 
             
                  include Mutex_m
         | 
| 38 28 | 
             
                end
         | 
| 39 29 |  | 
| 30 | 
            +
                class << self
         | 
| 31 | 
            +
                  def dangerous_attribute_methods # :nodoc:
         | 
| 32 | 
            +
                    @dangerous_attribute_methods ||= (
         | 
| 33 | 
            +
                      Base.instance_methods +
         | 
| 34 | 
            +
                      Base.private_instance_methods -
         | 
| 35 | 
            +
                      Base.superclass.instance_methods -
         | 
| 36 | 
            +
                      Base.superclass.private_instance_methods
         | 
| 37 | 
            +
                    ).map { |m| -m.to_s }.to_set.freeze
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 40 41 | 
             
                module ClassMethods
         | 
| 41 42 | 
             
                  def inherited(child_class) #:nodoc:
         | 
| 42 43 | 
             
                    child_class.initialize_generated_modules
         | 
| @@ -44,7 +45,8 @@ module ActiveRecord | |
| 44 45 | 
             
                  end
         | 
| 45 46 |  | 
| 46 47 | 
             
                  def initialize_generated_modules # :nodoc:
         | 
| 47 | 
            -
                    @generated_attribute_methods = GeneratedAttributeMethods.new
         | 
| 48 | 
            +
                    @generated_attribute_methods = const_set(:GeneratedAttributeMethods, GeneratedAttributeMethods.new)
         | 
| 49 | 
            +
                    private_constant :GeneratedAttributeMethods
         | 
| 48 50 | 
             
                    @attribute_methods_generated = false
         | 
| 49 51 | 
             
                    include @generated_attribute_methods
         | 
| 50 52 |  | 
| @@ -59,7 +61,7 @@ module ActiveRecord | |
| 59 61 | 
             
                    # attribute methods.
         | 
| 60 62 | 
             
                    generated_attribute_methods.synchronize do
         | 
| 61 63 | 
             
                      return false if @attribute_methods_generated
         | 
| 62 | 
            -
                      superclass.define_attribute_methods unless  | 
| 64 | 
            +
                      superclass.define_attribute_methods unless base_class?
         | 
| 63 65 | 
             
                      super(attribute_names)
         | 
| 64 66 | 
             
                      @attribute_methods_generated = true
         | 
| 65 67 | 
             
                    end
         | 
| @@ -105,7 +107,7 @@ module ActiveRecord | |
| 105 107 | 
             
                  # A method name is 'dangerous' if it is already (re)defined by Active Record, but
         | 
| 106 108 | 
             
                  # not by any ancestors. (So 'puts' is not dangerous but 'save' is.)
         | 
| 107 109 | 
             
                  def dangerous_attribute_method?(name) # :nodoc:
         | 
| 108 | 
            -
                     | 
| 110 | 
            +
                    ::ActiveRecord::AttributeMethods.dangerous_attribute_methods.include?(name.to_s)
         | 
| 109 111 | 
             
                  end
         | 
| 110 112 |  | 
| 111 113 | 
             
                  def method_defined_within?(name, klass, superklass = klass.superclass) # :nodoc:
         | 
| @@ -123,13 +125,11 @@ module ActiveRecord | |
| 123 125 | 
             
                  # A class method is 'dangerous' if it is already (re)defined by Active Record, but
         | 
| 124 126 | 
             
                  # not by any ancestors. (So 'puts' is not dangerous but 'new' is.)
         | 
| 125 127 | 
             
                  def dangerous_class_method?(method_name)
         | 
| 126 | 
            -
                     | 
| 127 | 
            -
                  end
         | 
| 128 | 
            +
                    return true if RESTRICTED_CLASS_METHODS.include?(method_name.to_s)
         | 
| 128 129 |  | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 131 | 
            -
             | 
| 132 | 
            -
                        klass.method(name).owner != superklass.method(name).owner
         | 
| 130 | 
            +
                    if Base.respond_to?(method_name, true)
         | 
| 131 | 
            +
                      if Object.respond_to?(method_name, true)
         | 
| 132 | 
            +
                        Base.method(method_name).owner != Object.method(method_name).owner
         | 
| 133 133 | 
             
                      else
         | 
| 134 134 | 
             
                        true
         | 
| 135 135 | 
             
                      end
         | 
| @@ -148,7 +148,7 @@ module ActiveRecord | |
| 148 148 | 
             
                  #   Person.attribute_method?(:age=)    # => true
         | 
| 149 149 | 
             
                  #   Person.attribute_method?(:nothing) # => false
         | 
| 150 150 | 
             
                  def attribute_method?(attribute)
         | 
| 151 | 
            -
                    super || (table_exists? && column_names.include?(attribute.to_s. | 
| 151 | 
            +
                    super || (table_exists? && column_names.include?(attribute.to_s.delete_suffix("=")))
         | 
| 152 152 | 
             
                  end
         | 
| 153 153 |  | 
| 154 154 | 
             
                  # Returns an array of column names as strings if it's not an abstract class and
         | 
| @@ -164,90 +164,27 @@ module ActiveRecord | |
| 164 164 | 
             
                      attribute_types.keys
         | 
| 165 165 | 
             
                    else
         | 
| 166 166 | 
             
                      []
         | 
| 167 | 
            -
                    end
         | 
| 168 | 
            -
                  end
         | 
| 169 | 
            -
             | 
| 170 | 
            -
                  # Regexp whitelist. Matches the following:
         | 
| 171 | 
            -
                  #   "#{table_name}.#{column_name}"
         | 
| 172 | 
            -
                  #   "#{column_name}"
         | 
| 173 | 
            -
                  COLUMN_NAME_WHITELIST = /\A(?:\w+\.)?\w+\z/i
         | 
| 174 | 
            -
             | 
| 175 | 
            -
                  # Regexp whitelist. Matches the following:
         | 
| 176 | 
            -
                  #   "#{table_name}.#{column_name}"
         | 
| 177 | 
            -
                  #   "#{table_name}.#{column_name} #{direction}"
         | 
| 178 | 
            -
                  #   "#{table_name}.#{column_name} #{direction} NULLS FIRST"
         | 
| 179 | 
            -
                  #   "#{table_name}.#{column_name} NULLS LAST"
         | 
| 180 | 
            -
                  #   "#{column_name}"
         | 
| 181 | 
            -
                  #   "#{column_name} #{direction}"
         | 
| 182 | 
            -
                  #   "#{column_name} #{direction} NULLS FIRST"
         | 
| 183 | 
            -
                  #   "#{column_name} NULLS LAST"
         | 
| 184 | 
            -
                  COLUMN_NAME_ORDER_WHITELIST = /
         | 
| 185 | 
            -
                    \A
         | 
| 186 | 
            -
                    (?:\w+\.)?
         | 
| 187 | 
            -
                    \w+
         | 
| 188 | 
            -
                    (?:\s+asc|\s+desc)?
         | 
| 189 | 
            -
                    (?:\s+nulls\s+(?:first|last))?
         | 
| 190 | 
            -
                    \z
         | 
| 191 | 
            -
                  /ix
         | 
| 192 | 
            -
             | 
| 193 | 
            -
                  def enforce_raw_sql_whitelist(args, whitelist: COLUMN_NAME_WHITELIST) # :nodoc:
         | 
| 194 | 
            -
                    unexpected = args.reject do |arg|
         | 
| 195 | 
            -
                      arg.kind_of?(Arel::Node) ||
         | 
| 196 | 
            -
                        arg.is_a?(Arel::Nodes::SqlLiteral) ||
         | 
| 197 | 
            -
                        arg.is_a?(Arel::Attributes::Attribute) ||
         | 
| 198 | 
            -
                        arg.to_s.split(/\s*,\s*/).all? { |part| whitelist.match?(part) }
         | 
| 199 | 
            -
                    end
         | 
| 200 | 
            -
             | 
| 201 | 
            -
                    return if unexpected.none?
         | 
| 202 | 
            -
             | 
| 203 | 
            -
                    if allow_unsafe_raw_sql == :deprecated
         | 
| 204 | 
            -
                      ActiveSupport::Deprecation.warn(
         | 
| 205 | 
            -
                        "Dangerous query method (method whose arguments are used as raw " \
         | 
| 206 | 
            -
                        "SQL) called with non-attribute argument(s): " \
         | 
| 207 | 
            -
                        "#{unexpected.map(&:inspect).join(", ")}. Non-attribute " \
         | 
| 208 | 
            -
                        "arguments will be disallowed in Rails 6.0. This method should " \
         | 
| 209 | 
            -
                        "not be called with user-provided values, such as request " \
         | 
| 210 | 
            -
                        "parameters or model attributes. Known-safe values can be passed " \
         | 
| 211 | 
            -
                        "by wrapping them in Arel.sql()."
         | 
| 212 | 
            -
                      )
         | 
| 213 | 
            -
                    else
         | 
| 214 | 
            -
                      raise(ActiveRecord::UnknownAttributeReference,
         | 
| 215 | 
            -
                        "Query method called with non-attribute argument(s): " +
         | 
| 216 | 
            -
                        unexpected.map(&:inspect).join(", ")
         | 
| 217 | 
            -
                      )
         | 
| 218 | 
            -
                    end
         | 
| 167 | 
            +
                    end.freeze
         | 
| 219 168 | 
             
                  end
         | 
| 220 169 |  | 
| 221 170 | 
             
                  # Returns true if the given attribute exists, otherwise false.
         | 
| 222 171 | 
             
                  #
         | 
| 223 172 | 
             
                  #   class Person < ActiveRecord::Base
         | 
| 173 | 
            +
                  #     alias_attribute :new_name, :name
         | 
| 224 174 | 
             
                  #   end
         | 
| 225 175 | 
             
                  #
         | 
| 226 | 
            -
                  #   Person.has_attribute?('name') | 
| 227 | 
            -
                  #   Person.has_attribute?( | 
| 228 | 
            -
                  #   Person.has_attribute?(: | 
| 176 | 
            +
                  #   Person.has_attribute?('name')     # => true
         | 
| 177 | 
            +
                  #   Person.has_attribute?('new_name') # => true
         | 
| 178 | 
            +
                  #   Person.has_attribute?(:age)       # => true
         | 
| 179 | 
            +
                  #   Person.has_attribute?(:nothing)   # => false
         | 
| 229 180 | 
             
                  def has_attribute?(attr_name)
         | 
| 230 | 
            -
                     | 
| 181 | 
            +
                    attr_name = attr_name.to_s
         | 
| 182 | 
            +
                    attr_name = attribute_aliases[attr_name] || attr_name
         | 
| 183 | 
            +
                    attribute_types.key?(attr_name)
         | 
| 231 184 | 
             
                  end
         | 
| 232 185 |  | 
| 233 | 
            -
                   | 
| 234 | 
            -
             | 
| 235 | 
            -
                  # named attribute does not exist.
         | 
| 236 | 
            -
                  #
         | 
| 237 | 
            -
                  #   class Person < ActiveRecord::Base
         | 
| 238 | 
            -
                  #   end
         | 
| 239 | 
            -
                  #
         | 
| 240 | 
            -
                  #   person = Person.new
         | 
| 241 | 
            -
                  #   person.column_for_attribute(:name) # the result depends on the ConnectionAdapter
         | 
| 242 | 
            -
                  #   # => #<ActiveRecord::ConnectionAdapters::Column:0x007ff4ab083980 @name="name", @sql_type="varchar(255)", @null=true, ...>
         | 
| 243 | 
            -
                  #
         | 
| 244 | 
            -
                  #   person.column_for_attribute(:nothing)
         | 
| 245 | 
            -
                  #   # => #<ActiveRecord::ConnectionAdapters::NullColumn:0xXXX @name=nil, @sql_type=nil, @cast_type=#<Type::Value>, ...>
         | 
| 246 | 
            -
                  def column_for_attribute(name)
         | 
| 247 | 
            -
                    name = name.to_s
         | 
| 248 | 
            -
                    columns_hash.fetch(name) do
         | 
| 249 | 
            -
                      ConnectionAdapters::NullColumn.new(name)
         | 
| 250 | 
            -
                    end
         | 
| 186 | 
            +
                  def _has_attribute?(attr_name) # :nodoc:
         | 
| 187 | 
            +
                    attribute_types.key?(attr_name)
         | 
| 251 188 | 
             
                  end
         | 
| 252 189 | 
             
                end
         | 
| 253 190 |  | 
| @@ -270,21 +207,14 @@ module ActiveRecord | |
| 270 207 | 
             
                def respond_to?(name, include_private = false)
         | 
| 271 208 | 
             
                  return false unless super
         | 
| 272 209 |  | 
| 273 | 
            -
                  case name
         | 
| 274 | 
            -
                  when :to_partial_path
         | 
| 275 | 
            -
                    name = "to_partial_path".freeze
         | 
| 276 | 
            -
                  when :to_model
         | 
| 277 | 
            -
                    name = "to_model".freeze
         | 
| 278 | 
            -
                  else
         | 
| 279 | 
            -
                    name = name.to_s
         | 
| 280 | 
            -
                  end
         | 
| 281 | 
            -
             | 
| 282 210 | 
             
                  # If the result is true then check for the select case.
         | 
| 283 211 | 
             
                  # For queries selecting a subset of columns, return false for unselected columns.
         | 
| 284 212 | 
             
                  # We check defined?(@attributes) not to issue warnings if called on objects that
         | 
| 285 213 | 
             
                  # have been allocated but not yet initialized.
         | 
| 286 | 
            -
                  if defined?(@attributes) | 
| 287 | 
            -
                     | 
| 214 | 
            +
                  if defined?(@attributes)
         | 
| 215 | 
            +
                    if name = self.class.symbol_column_to_string(name.to_sym)
         | 
| 216 | 
            +
                      return _has_attribute?(name)
         | 
| 217 | 
            +
                    end
         | 
| 288 218 | 
             
                  end
         | 
| 289 219 |  | 
| 290 220 | 
             
                  true
         | 
| @@ -293,14 +223,22 @@ module ActiveRecord | |
| 293 223 | 
             
                # Returns +true+ if the given attribute is in the attributes hash, otherwise +false+.
         | 
| 294 224 | 
             
                #
         | 
| 295 225 | 
             
                #   class Person < ActiveRecord::Base
         | 
| 226 | 
            +
                #     alias_attribute :new_name, :name
         | 
| 296 227 | 
             
                #   end
         | 
| 297 228 | 
             
                #
         | 
| 298 229 | 
             
                #   person = Person.new
         | 
| 299 | 
            -
                #   person.has_attribute?(:name) | 
| 300 | 
            -
                #   person.has_attribute?( | 
| 301 | 
            -
                #   person.has_attribute?( | 
| 230 | 
            +
                #   person.has_attribute?(:name)     # => true
         | 
| 231 | 
            +
                #   person.has_attribute?(:new_name) # => true
         | 
| 232 | 
            +
                #   person.has_attribute?('age')     # => true
         | 
| 233 | 
            +
                #   person.has_attribute?(:nothing)  # => false
         | 
| 302 234 | 
             
                def has_attribute?(attr_name)
         | 
| 303 | 
            -
                   | 
| 235 | 
            +
                  attr_name = attr_name.to_s
         | 
| 236 | 
            +
                  attr_name = self.class.attribute_aliases[attr_name] || attr_name
         | 
| 237 | 
            +
                  @attributes.key?(attr_name)
         | 
| 238 | 
            +
                end
         | 
| 239 | 
            +
             | 
| 240 | 
            +
                def _has_attribute?(attr_name) # :nodoc:
         | 
| 241 | 
            +
                  @attributes.key?(attr_name)
         | 
| 304 242 | 
             
                end
         | 
| 305 243 |  | 
| 306 244 | 
             
                # Returns an array of names for the attributes available on this object.
         | 
| @@ -344,15 +282,10 @@ module ActiveRecord | |
| 344 282 | 
             
                #   person.attribute_for_inspect(:tag_ids)
         | 
| 345 283 | 
             
                #   # => "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]"
         | 
| 346 284 | 
             
                def attribute_for_inspect(attr_name)
         | 
| 347 | 
            -
                   | 
| 348 | 
            -
             | 
| 349 | 
            -
                   | 
| 350 | 
            -
             | 
| 351 | 
            -
                  elsif value.is_a?(Date) || value.is_a?(Time)
         | 
| 352 | 
            -
                    %("#{value.to_s(:db)}")
         | 
| 353 | 
            -
                  else
         | 
| 354 | 
            -
                    value.inspect
         | 
| 355 | 
            -
                  end
         | 
| 285 | 
            +
                  attr_name = attr_name.to_s
         | 
| 286 | 
            +
                  attr_name = self.class.attribute_aliases[attr_name] || attr_name
         | 
| 287 | 
            +
                  value = _read_attribute(attr_name)
         | 
| 288 | 
            +
                  format_for_inspect(attr_name, value)
         | 
| 356 289 | 
             
                end
         | 
| 357 290 |  | 
| 358 291 | 
             
                # Returns +true+ if the specified +attribute+ has been set by the user or by a
         | 
| @@ -370,8 +303,10 @@ module ActiveRecord | |
| 370 303 | 
             
                #   task.is_done = true
         | 
| 371 304 | 
             
                #   task.attribute_present?(:title)   # => true
         | 
| 372 305 | 
             
                #   task.attribute_present?(:is_done) # => true
         | 
| 373 | 
            -
                def attribute_present?( | 
| 374 | 
            -
                   | 
| 306 | 
            +
                def attribute_present?(attr_name)
         | 
| 307 | 
            +
                  attr_name = attr_name.to_s
         | 
| 308 | 
            +
                  attr_name = self.class.attribute_aliases[attr_name] || attr_name
         | 
| 309 | 
            +
                  value = _read_attribute(attr_name)
         | 
| 375 310 | 
             
                  !value.nil? && !(value.respond_to?(:empty?) && value.empty?)
         | 
| 376 311 | 
             
                end
         | 
| 377 312 |  | 
| @@ -443,50 +378,53 @@ module ActiveRecord | |
| 443 378 | 
             
                  @attributes.accessed
         | 
| 444 379 | 
             
                end
         | 
| 445 380 |  | 
| 446 | 
            -
                 | 
| 447 | 
            -
             | 
| 448 | 
            -
                  def attribute_method?(attr_name) # :nodoc:
         | 
| 381 | 
            +
                private
         | 
| 382 | 
            +
                  def attribute_method?(attr_name)
         | 
| 449 383 | 
             
                    # We check defined? because Syck calls respond_to? before actually calling initialize.
         | 
| 450 384 | 
             
                    defined?(@attributes) && @attributes.key?(attr_name)
         | 
| 451 385 | 
             
                  end
         | 
| 452 386 |  | 
| 453 | 
            -
                private
         | 
| 454 | 
            -
             | 
| 455 | 
            -
                  def attributes_with_values_for_create(attribute_names)
         | 
| 456 | 
            -
                    attributes_with_values(attributes_for_create(attribute_names))
         | 
| 457 | 
            -
                  end
         | 
| 458 | 
            -
             | 
| 459 | 
            -
                  def attributes_with_values_for_update(attribute_names)
         | 
| 460 | 
            -
                    attributes_with_values(attributes_for_update(attribute_names))
         | 
| 461 | 
            -
                  end
         | 
| 462 | 
            -
             | 
| 463 387 | 
             
                  def attributes_with_values(attribute_names)
         | 
| 464 | 
            -
                    attribute_names. | 
| 465 | 
            -
                       | 
| 388 | 
            +
                    attribute_names.index_with do |name|
         | 
| 389 | 
            +
                      _read_attribute(name)
         | 
| 466 390 | 
             
                    end
         | 
| 467 391 | 
             
                  end
         | 
| 468 392 |  | 
| 469 393 | 
             
                  # Filters the primary keys and readonly attributes from the attribute names.
         | 
| 470 394 | 
             
                  def attributes_for_update(attribute_names)
         | 
| 471 | 
            -
                    attribute_names | 
| 472 | 
            -
             | 
| 395 | 
            +
                    attribute_names &= self.class.column_names
         | 
| 396 | 
            +
                    attribute_names.delete_if do |name|
         | 
| 397 | 
            +
                      self.class.readonly_attribute?(name)
         | 
| 473 398 | 
             
                    end
         | 
| 474 399 | 
             
                  end
         | 
| 475 400 |  | 
| 476 401 | 
             
                  # Filters out the primary keys, from the attribute names, when the primary
         | 
| 477 402 | 
             
                  # key is to be generated (e.g. the id attribute has no value).
         | 
| 478 403 | 
             
                  def attributes_for_create(attribute_names)
         | 
| 479 | 
            -
                    attribute_names | 
| 404 | 
            +
                    attribute_names &= self.class.column_names
         | 
| 405 | 
            +
                    attribute_names.delete_if do |name|
         | 
| 480 406 | 
             
                      pk_attribute?(name) && id.nil?
         | 
| 481 407 | 
             
                    end
         | 
| 482 408 | 
             
                  end
         | 
| 483 409 |  | 
| 484 | 
            -
                  def  | 
| 485 | 
            -
                     | 
| 410 | 
            +
                  def format_for_inspect(name, value)
         | 
| 411 | 
            +
                    if value.nil?
         | 
| 412 | 
            +
                      value.inspect
         | 
| 413 | 
            +
                    else
         | 
| 414 | 
            +
                      inspected_value = if value.is_a?(String) && value.length > 50
         | 
| 415 | 
            +
                        "#{value[0, 50]}...".inspect
         | 
| 416 | 
            +
                      elsif value.is_a?(Date) || value.is_a?(Time)
         | 
| 417 | 
            +
                        %("#{value.to_s(:inspect)}")
         | 
| 418 | 
            +
                      else
         | 
| 419 | 
            +
                        value.inspect
         | 
| 420 | 
            +
                      end
         | 
| 421 | 
            +
             | 
| 422 | 
            +
                      inspection_filter.filter_param(name, inspected_value)
         | 
| 423 | 
            +
                    end
         | 
| 486 424 | 
             
                  end
         | 
| 487 425 |  | 
| 488 426 | 
             
                  def pk_attribute?(name)
         | 
| 489 | 
            -
                    name ==  | 
| 427 | 
            +
                    name == @primary_key
         | 
| 490 428 | 
             
                  end
         | 
| 491 429 | 
             
              end
         | 
| 492 430 | 
             
            end
         | 
| @@ -12,6 +12,9 @@ module ActiveRecord | |
| 12 12 | 
             
                end
         | 
| 13 13 |  | 
| 14 14 | 
             
                module ClassMethods
         | 
| 15 | 
            +
                  ##
         | 
| 16 | 
            +
                  # :call-seq: attribute(name, cast_type = nil, **options)
         | 
| 17 | 
            +
                  #
         | 
| 15 18 | 
             
                  # Defines an attribute with a type on this model. It will override the
         | 
| 16 19 | 
             
                  # type of existing attributes if needed. This allows control over how
         | 
| 17 20 | 
             
                  # values are converted to and from SQL when assigned to a model. It also
         | 
| @@ -41,6 +44,9 @@ module ActiveRecord | |
| 41 44 | 
             
                  # +range+ (PostgreSQL only) specifies that the type should be a range (see the
         | 
| 42 45 | 
             
                  # examples below).
         | 
| 43 46 | 
             
                  #
         | 
| 47 | 
            +
                  # When using a symbol for +cast_type+, extra options are forwarded to the
         | 
| 48 | 
            +
                  # constructor of the type object.
         | 
| 49 | 
            +
                  #
         | 
| 44 50 | 
             
                  # ==== Examples
         | 
| 45 51 | 
             
                  #
         | 
| 46 52 | 
             
                  # The type detected by Active Record can be overridden.
         | 
| @@ -112,6 +118,16 @@ module ActiveRecord | |
| 112 118 | 
             
                  #       my_float_range: 1.0..3.5
         | 
| 113 119 | 
             
                  #     }
         | 
| 114 120 | 
             
                  #
         | 
| 121 | 
            +
                  # Passing options to the type constructor
         | 
| 122 | 
            +
                  #
         | 
| 123 | 
            +
                  #   # app/models/my_model.rb
         | 
| 124 | 
            +
                  #   class MyModel < ActiveRecord::Base
         | 
| 125 | 
            +
                  #     attribute :small_int, :integer, limit: 2
         | 
| 126 | 
            +
                  #   end
         | 
| 127 | 
            +
                  #
         | 
| 128 | 
            +
                  #   MyModel.create(small_int: 65537)
         | 
| 129 | 
            +
                  #   # => Error: 65537 is out of range for the limit of two bytes
         | 
| 130 | 
            +
                  #
         | 
| 115 131 | 
             
                  # ==== Creating Custom Types
         | 
| 116 132 | 
             
                  #
         | 
| 117 133 | 
             
                  # Users may also define their own custom types, as long as they respond
         | 
| @@ -192,13 +208,13 @@ module ActiveRecord | |
| 192 208 | 
             
                  # tracking is performed. The methods +changed?+ and +changed_in_place?+
         | 
| 193 209 | 
             
                  # will be called from ActiveModel::Dirty. See the documentation for those
         | 
| 194 210 | 
             
                  # methods in ActiveModel::Type::Value for more details.
         | 
| 195 | 
            -
                  def attribute(name, cast_type =  | 
| 211 | 
            +
                  def attribute(name, cast_type = nil, **options, &block)
         | 
| 196 212 | 
             
                    name = name.to_s
         | 
| 197 213 | 
             
                    reload_schema_from_cache
         | 
| 198 214 |  | 
| 199 215 | 
             
                    self.attributes_to_define_after_schema_loads =
         | 
| 200 216 | 
             
                      attributes_to_define_after_schema_loads.merge(
         | 
| 201 | 
            -
                        name => [cast_type, options]
         | 
| 217 | 
            +
                        name => [cast_type || block, options]
         | 
| 202 218 | 
             
                      )
         | 
| 203 219 | 
             
                  end
         | 
| 204 220 |  | 
| @@ -233,16 +249,11 @@ module ActiveRecord | |
| 233 249 | 
             
                  def load_schema! # :nodoc:
         | 
| 234 250 | 
             
                    super
         | 
| 235 251 | 
             
                    attributes_to_define_after_schema_loads.each do |name, (type, options)|
         | 
| 236 | 
            -
                       | 
| 237 | 
            -
                        type = ActiveRecord::Type.lookup(type, **options.except(:default))
         | 
| 238 | 
            -
                      end
         | 
| 239 | 
            -
             | 
| 240 | 
            -
                      define_attribute(name, type, **options.slice(:default))
         | 
| 252 | 
            +
                      define_attribute(name, _lookup_cast_type(name, type, options), **options.slice(:default))
         | 
| 241 253 | 
             
                    end
         | 
| 242 254 | 
             
                  end
         | 
| 243 255 |  | 
| 244 256 | 
             
                  private
         | 
| 245 | 
            -
             | 
| 246 257 | 
             
                    NO_DEFAULT_PROVIDED = Object.new # :nodoc:
         | 
| 247 258 | 
             
                    private_constant :NO_DEFAULT_PROVIDED
         | 
| 248 259 |  | 
| @@ -261,6 +272,32 @@ module ActiveRecord | |
| 261 272 | 
             
                      end
         | 
| 262 273 | 
             
                      _default_attributes[name] = default_attribute
         | 
| 263 274 | 
             
                    end
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                    def decorate_attribute_type(attr_name, **default)
         | 
| 277 | 
            +
                      type, options = attributes_to_define_after_schema_loads[attr_name]
         | 
| 278 | 
            +
             | 
| 279 | 
            +
                      default.with_defaults!(default: options[:default]) if options&.key?(:default)
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                      attribute(attr_name, **default) do |cast_type|
         | 
| 282 | 
            +
                        if type && !type.is_a?(Proc)
         | 
| 283 | 
            +
                          cast_type = _lookup_cast_type(attr_name, type, options)
         | 
| 284 | 
            +
                        end
         | 
| 285 | 
            +
             | 
| 286 | 
            +
                        yield cast_type
         | 
| 287 | 
            +
                      end
         | 
| 288 | 
            +
                    end
         | 
| 289 | 
            +
             | 
| 290 | 
            +
                    def _lookup_cast_type(name, type, options)
         | 
| 291 | 
            +
                      case type
         | 
| 292 | 
            +
                      when Symbol
         | 
| 293 | 
            +
                        adapter_name = ActiveRecord::Type.adapter_name_from(self)
         | 
| 294 | 
            +
                        ActiveRecord::Type.lookup(type, **options.except(:default), adapter: adapter_name)
         | 
| 295 | 
            +
                      when Proc
         | 
| 296 | 
            +
                        type[type_for_attribute(name)]
         | 
| 297 | 
            +
                      else
         | 
| 298 | 
            +
                        type || type_for_attribute(name)
         | 
| 299 | 
            +
                      end
         | 
| 300 | 
            +
                    end
         | 
| 264 301 | 
             
                end
         | 
| 265 302 | 
             
              end
         | 
| 266 303 | 
             
            end
         | 
| @@ -29,9 +29,9 @@ module ActiveRecord | |
| 29 29 | 
             
              # == Callbacks
         | 
| 30 30 | 
             
              #
         | 
| 31 31 | 
             
              # Association with autosave option defines several callbacks on your
         | 
| 32 | 
            -
              # model (before_save, after_create, after_update). Please note that
         | 
| 32 | 
            +
              # model (around_save, before_save, after_create, after_update). Please note that
         | 
| 33 33 | 
             
              # callbacks are executed in the order they were defined in
         | 
| 34 | 
            -
              # model. You should avoid modifying the association content | 
| 34 | 
            +
              # model. You should avoid modifying the association content before
         | 
| 35 35 | 
             
              # autosave callbacks are executed. Placing your callbacks after
         | 
| 36 36 | 
             
              # associations is usually a good practice.
         | 
| 37 37 | 
             
              #
         | 
| @@ -91,8 +91,9 @@ module ActiveRecord | |
| 91 91 | 
             
              #   post.save # => saves both post and comment
         | 
| 92 92 | 
             
              #
         | 
| 93 93 | 
             
              #   post = Post.create(title: 'ruby rocks')
         | 
| 94 | 
            -
              #   post.comments.create(body: 'hello world')
         | 
| 95 | 
            -
              #    | 
| 94 | 
            +
              #   comment = post.comments.create(body: 'hello world')
         | 
| 95 | 
            +
              #   comment.body = 'hi everyone'
         | 
| 96 | 
            +
              #   post.save # => saves post, but not comment
         | 
| 96 97 | 
             
              #
         | 
| 97 98 | 
             
              # When <tt>:autosave</tt> is true all children are saved, no matter whether they
         | 
| 98 99 | 
             
              # are new records or not:
         | 
| @@ -102,11 +103,10 @@ module ActiveRecord | |
| 102 103 | 
             
              #   end
         | 
| 103 104 | 
             
              #
         | 
| 104 105 | 
             
              #   post = Post.create(title: 'ruby rocks')
         | 
| 105 | 
            -
              #   post.comments.create(body: 'hello world')
         | 
| 106 | 
            -
              #    | 
| 106 | 
            +
              #   comment = post.comments.create(body: 'hello world')
         | 
| 107 | 
            +
              #   comment.body = 'hi everyone'
         | 
| 107 108 | 
             
              #   post.comments.build(body: "good morning.")
         | 
| 108 | 
            -
              #   post. | 
| 109 | 
            -
              #   post.save # => saves both post and comments.
         | 
| 109 | 
            +
              #   post.save # => saves post and both comments.
         | 
| 110 110 | 
             
              #
         | 
| 111 111 | 
             
              # Destroying one of the associated models as part of the parent's save action
         | 
| 112 112 | 
             
              # is as simple as marking it for destruction:
         | 
| @@ -127,6 +127,14 @@ module ActiveRecord | |
| 127 127 | 
             
              # Now it _is_ removed from the database:
         | 
| 128 128 | 
             
              #
         | 
| 129 129 | 
             
              #   Comment.find_by(id: id).nil? # => true
         | 
| 130 | 
            +
              #
         | 
| 131 | 
            +
              # === Caveats
         | 
| 132 | 
            +
              #
         | 
| 133 | 
            +
              # Note that autosave will only trigger for already-persisted association records
         | 
| 134 | 
            +
              # if the records themselves have been changed. This is to protect against
         | 
| 135 | 
            +
              # <tt>SystemStackError</tt> caused by circular association validations. The one
         | 
| 136 | 
            +
              # exception is if a custom validation context is used, in which case the validations
         | 
| 137 | 
            +
              # will always fire on the associated records.
         | 
| 130 138 | 
             
              module AutosaveAssociation
         | 
| 131 139 | 
             
                extend ActiveSupport::Concern
         | 
| 132 140 |  | 
| @@ -147,9 +155,23 @@ module ActiveRecord | |
| 147 155 |  | 
| 148 156 | 
             
                module ClassMethods # :nodoc:
         | 
| 149 157 | 
             
                  private
         | 
| 158 | 
            +
                    if Module.method(:method_defined?).arity == 1 # MRI 2.5 and older
         | 
| 159 | 
            +
                      using Module.new {
         | 
| 160 | 
            +
                        refine Module do
         | 
| 161 | 
            +
                          def method_defined?(method, inherit = true)
         | 
| 162 | 
            +
                            if inherit
         | 
| 163 | 
            +
                              super(method)
         | 
| 164 | 
            +
                            else
         | 
| 165 | 
            +
                              instance_methods(false).include?(method.to_sym)
         | 
| 166 | 
            +
                            end
         | 
| 167 | 
            +
                          end
         | 
| 168 | 
            +
                        end
         | 
| 169 | 
            +
                      }
         | 
| 170 | 
            +
                    end
         | 
| 150 171 |  | 
| 151 172 | 
             
                    def define_non_cyclic_method(name, &block)
         | 
| 152 | 
            -
                      return if method_defined?(name)
         | 
| 173 | 
            +
                      return if method_defined?(name, false)
         | 
| 174 | 
            +
             | 
| 153 175 | 
             
                      define_method(name) do |*args|
         | 
| 154 176 | 
             
                        result = true; @_already_called ||= {}
         | 
| 155 177 | 
             
                        # Loop prevention for validation of associations
         | 
| @@ -181,8 +203,7 @@ module ActiveRecord | |
| 181 203 | 
             
                      save_method = :"autosave_associated_records_for_#{reflection.name}"
         | 
| 182 204 |  | 
| 183 205 | 
             
                      if reflection.collection?
         | 
| 184 | 
            -
                         | 
| 185 | 
            -
                        after_save :after_save_collection_association
         | 
| 206 | 
            +
                        around_save :around_save_collection_association
         | 
| 186 207 |  | 
| 187 208 | 
             
                        define_non_cyclic_method(save_method) { save_collection_association(reflection) }
         | 
| 188 209 | 
             
                        # Doesn't use after_save as that would save associations added in after_create/after_update twice
         | 
| @@ -267,7 +288,6 @@ module ActiveRecord | |
| 267 288 | 
             
                end
         | 
| 268 289 |  | 
| 269 290 | 
             
                private
         | 
| 270 | 
            -
             | 
| 271 291 | 
             
                  # Returns the record for an association collection that should be validated
         | 
| 272 292 | 
             
                  # or saved. If +autosave+ is +false+ only new records will be returned,
         | 
| 273 293 | 
             
                  # unless the parent is/was a new record itself.
         | 
| @@ -281,8 +301,9 @@ module ActiveRecord | |
| 281 301 | 
             
                    end
         | 
| 282 302 | 
             
                  end
         | 
| 283 303 |  | 
| 284 | 
            -
                  #  | 
| 285 | 
            -
                  # any new ones), and return true if  | 
| 304 | 
            +
                  # Go through nested autosave associations that are loaded in memory (without loading
         | 
| 305 | 
            +
                  # any new ones), and return true if any are changed for autosave.
         | 
| 306 | 
            +
                  # Returns false if already called to prevent an infinite loop.
         | 
| 286 307 | 
             
                  def nested_records_changed_for_autosave?
         | 
| 287 308 | 
             
                    @_nested_records_changed_for_autosave_already_called ||= false
         | 
| 288 309 | 
             
                    return false if @_nested_records_changed_for_autosave_already_called
         | 
| @@ -330,21 +351,16 @@ module ActiveRecord | |
| 330 351 | 
             
                      if reflection.options[:autosave]
         | 
| 331 352 | 
             
                        indexed_attribute = !index.nil? && (reflection.options[:index_errors] || ActiveRecord::Base.index_nested_attribute_errors)
         | 
| 332 353 |  | 
| 333 | 
            -
                        record.errors.each  | 
| 354 | 
            +
                        record.errors.group_by_attribute.each { |attribute, errors|
         | 
| 334 355 | 
             
                          attribute = normalize_reflection_attribute(indexed_attribute, reflection, index, attribute)
         | 
| 335 | 
            -
                          errors[attribute] << message
         | 
| 336 | 
            -
                          errors[attribute].uniq!
         | 
| 337 | 
            -
                        end
         | 
| 338 356 |  | 
| 339 | 
            -
             | 
| 340 | 
            -
             | 
| 341 | 
            -
             | 
| 342 | 
            -
             | 
| 343 | 
            -
             | 
| 344 | 
            -
             | 
| 345 | 
            -
             | 
| 346 | 
            -
                          end
         | 
| 347 | 
            -
                        end
         | 
| 357 | 
            +
                          errors.each { |error|
         | 
| 358 | 
            +
                            self.errors.import(
         | 
| 359 | 
            +
                              error,
         | 
| 360 | 
            +
                              attribute: attribute
         | 
| 361 | 
            +
                            )
         | 
| 362 | 
            +
                          }
         | 
| 363 | 
            +
                        }
         | 
| 348 364 | 
             
                      else
         | 
| 349 365 | 
             
                        errors.add(reflection.name)
         | 
| 350 366 | 
             
                      end
         | 
| @@ -360,14 +376,15 @@ module ActiveRecord | |
| 360 376 | 
             
                    end
         | 
| 361 377 | 
             
                  end
         | 
| 362 378 |  | 
| 363 | 
            -
                  # Is used as  | 
| 379 | 
            +
                  # Is used as an around_save callback to check while saving a collection
         | 
| 364 380 | 
             
                  # association whether or not the parent was a new record before saving.
         | 
| 365 | 
            -
                  def  | 
| 366 | 
            -
                    @new_record_before_save  | 
| 367 | 
            -
             | 
| 381 | 
            +
                  def around_save_collection_association
         | 
| 382 | 
            +
                    previously_new_record_before_save = (@new_record_before_save ||= false)
         | 
| 383 | 
            +
                    @new_record_before_save = !previously_new_record_before_save && new_record?
         | 
| 368 384 |  | 
| 369 | 
            -
             | 
| 370 | 
            -
             | 
| 385 | 
            +
                    yield
         | 
| 386 | 
            +
                  ensure
         | 
| 387 | 
            +
                    @new_record_before_save = previously_new_record_before_save
         | 
| 371 388 | 
             
                  end
         | 
| 372 389 |  | 
| 373 390 | 
             
                  # Saves any new associated records, or all loaded autosave associations if
         | 
| @@ -416,7 +433,7 @@ module ActiveRecord | |
| 416 433 | 
             
                            saved = record.save(validate: false)
         | 
| 417 434 | 
             
                          end
         | 
| 418 435 |  | 
| 419 | 
            -
                          raise  | 
| 436 | 
            +
                          raise(RecordInvalid.new(association.owner)) unless saved
         | 
| 420 437 | 
             
                        end
         | 
| 421 438 | 
             
                      end
         | 
| 422 439 | 
             
                    end
         | 
| @@ -440,13 +457,13 @@ module ActiveRecord | |
| 440 457 | 
             
                      if autosave && record.marked_for_destruction?
         | 
| 441 458 | 
             
                        record.destroy
         | 
| 442 459 | 
             
                      elsif autosave != false
         | 
| 443 | 
            -
                        key = reflection.options[:primary_key] ?  | 
| 460 | 
            +
                        key = reflection.options[:primary_key] ? public_send(reflection.options[:primary_key]) : id
         | 
| 444 461 |  | 
| 445 | 
            -
                        if (autosave && record.changed_for_autosave?) ||  | 
| 462 | 
            +
                        if (autosave && record.changed_for_autosave?) || record_changed?(reflection, record, key)
         | 
| 446 463 | 
             
                          unless reflection.through_reflection
         | 
| 447 464 | 
             
                            record[reflection.foreign_key] = key
         | 
| 448 465 | 
             
                            if inverse_reflection = reflection.inverse_of
         | 
| 449 | 
            -
                              record.association(inverse_reflection.name). | 
| 466 | 
            +
                              record.association(inverse_reflection.name).inversed_from(self)
         | 
| 450 467 | 
             
                            end
         | 
| 451 468 | 
             
                          end
         | 
| 452 469 |  | 
| @@ -468,7 +485,7 @@ module ActiveRecord | |
| 468 485 | 
             
                  def association_foreign_key_changed?(reflection, record, key)
         | 
| 469 486 | 
             
                    return false if reflection.through_reflection?
         | 
| 470 487 |  | 
| 471 | 
            -
                    record. | 
| 488 | 
            +
                    record._has_attribute?(reflection.foreign_key) && record._read_attribute(reflection.foreign_key) != key
         | 
| 472 489 | 
             
                  end
         | 
| 473 490 |  | 
| 474 491 | 
             
                  # Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
         | 
| @@ -489,7 +506,7 @@ module ActiveRecord | |
| 489 506 | 
             
                        saved = record.save(validate: !autosave) if record.new_record? || (autosave && record.changed_for_autosave?)
         | 
| 490 507 |  | 
| 491 508 | 
             
                        if association.updated?
         | 
| 492 | 
            -
                          association_id = record. | 
| 509 | 
            +
                          association_id = record.public_send(reflection.options[:primary_key] || :id)
         | 
| 493 510 | 
             
                          self[reflection.foreign_key] = association_id
         | 
| 494 511 | 
             
                          association.loaded!
         | 
| 495 512 | 
             
                        end
         | 
| @@ -504,9 +521,7 @@ module ActiveRecord | |
| 504 521 | 
             
                  end
         | 
| 505 522 |  | 
| 506 523 | 
             
                  def _ensure_no_duplicate_errors
         | 
| 507 | 
            -
                    errors. | 
| 508 | 
            -
                      errors[attribute].uniq!
         | 
| 509 | 
            -
                    end
         | 
| 524 | 
            +
                    errors.uniq!
         | 
| 510 525 | 
             
                  end
         | 
| 511 526 | 
             
              end
         | 
| 512 527 | 
             
            end
         |