activerecord 5.2.3 → 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 +898 -532
- 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 +10 -19
- 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 +27 -28
- 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 +54 -12
- 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 +48 -35
- 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 +76 -47
- data/lib/active_record/base.rb +4 -17
- data/lib/active_record/callbacks.rb +158 -43
- data/lib/active_record/coders/yaml_column.rb +1 -2
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +293 -132
- 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 +21 -17
- 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 +175 -187
- 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 +308 -100
- 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 +3 -3
- 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 +115 -58
- 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 +113 -101
- 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 +157 -93
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +65 -40
- 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 +487 -199
- 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 +6 -8
- 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 +51 -8
- 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 +59 -117
- 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 +117 -32
- 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
| @@ -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,12 +288,11 @@ 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.
         | 
| 274 294 | 
             
                  def associated_records_to_validate_or_save(association, new_record, autosave)
         | 
| 275 | 
            -
                    if new_record
         | 
| 295 | 
            +
                    if new_record || custom_validation_context?
         | 
| 276 296 | 
             
                      association && association.target
         | 
| 277 297 | 
             
                    elsif autosave
         | 
| 278 298 | 
             
                      association.target.find_all(&:changed_for_autosave?)
         | 
| @@ -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
         | 
| @@ -304,7 +325,7 @@ module ActiveRecord | |
| 304 325 | 
             
                  def validate_single_association(reflection)
         | 
| 305 326 | 
             
                    association = association_instance_get(reflection.name)
         | 
| 306 327 | 
             
                    record      = association && association.reader
         | 
| 307 | 
            -
                    association_valid?(reflection, record) if record
         | 
| 328 | 
            +
                    association_valid?(reflection, record) if record && (record.changed_for_autosave? || custom_validation_context?)
         | 
| 308 329 | 
             
                  end
         | 
| 309 330 |  | 
| 310 331 | 
             
                  # Validate the associated records if <tt>:validate</tt> or
         | 
| @@ -324,27 +345,22 @@ module ActiveRecord | |
| 324 345 | 
             
                  def association_valid?(reflection, record, index = nil)
         | 
| 325 346 | 
             
                    return true if record.destroyed? || (reflection.options[:autosave] && record.marked_for_destruction?)
         | 
| 326 347 |  | 
| 327 | 
            -
                    context = validation_context  | 
| 348 | 
            +
                    context = validation_context if custom_validation_context?
         | 
| 328 349 |  | 
| 329 350 | 
             
                    unless valid = record.valid?(context)
         | 
| 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 | 
            -
             | 
| 339 | 
            -
                        record.errors.details.each_key do |attribute|
         | 
| 340 | 
            -
                          reflection_attribute =
         | 
| 341 | 
            -
                            normalize_reflection_attribute(indexed_attribute, reflection, index, attribute).to_sym
         | 
| 342 356 |  | 
| 343 | 
            -
                           | 
| 344 | 
            -
                            errors. | 
| 345 | 
            -
             | 
| 346 | 
            -
             | 
| 347 | 
            -
             | 
| 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
         | 
| @@ -382,10 +399,14 @@ module ActiveRecord | |
| 382 399 | 
             
                    if association = association_instance_get(reflection.name)
         | 
| 383 400 | 
             
                      autosave = reflection.options[:autosave]
         | 
| 384 401 |  | 
| 402 | 
            +
                      # By saving the instance variable in a local variable,
         | 
| 403 | 
            +
                      # we make the whole callback re-entrant.
         | 
| 404 | 
            +
                      new_record_before_save = @new_record_before_save
         | 
| 405 | 
            +
             | 
| 385 406 | 
             
                      # reconstruct the scope now that we know the owner's id
         | 
| 386 407 | 
             
                      association.reset_scope
         | 
| 387 408 |  | 
| 388 | 
            -
                      if records = associated_records_to_validate_or_save(association,  | 
| 409 | 
            +
                      if records = associated_records_to_validate_or_save(association, new_record_before_save, autosave)
         | 
| 389 410 | 
             
                        if autosave
         | 
| 390 411 | 
             
                          records_to_destroy = records.select(&:marked_for_destruction?)
         | 
| 391 412 | 
             
                          records_to_destroy.each { |record| association.destroy(record) }
         | 
| @@ -397,7 +418,7 @@ module ActiveRecord | |
| 397 418 |  | 
| 398 419 | 
             
                          saved = true
         | 
| 399 420 |  | 
| 400 | 
            -
                          if autosave != false && ( | 
| 421 | 
            +
                          if autosave != false && (new_record_before_save || record.new_record?)
         | 
| 401 422 | 
             
                            if autosave
         | 
| 402 423 | 
             
                              saved = association.insert_record(record, false)
         | 
| 403 424 | 
             
                            elsif !reflection.nested?
         | 
| @@ -412,7 +433,7 @@ module ActiveRecord | |
| 412 433 | 
             
                            saved = record.save(validate: false)
         | 
| 413 434 | 
             
                          end
         | 
| 414 435 |  | 
| 415 | 
            -
                          raise  | 
| 436 | 
            +
                          raise(RecordInvalid.new(association.owner)) unless saved
         | 
| 416 437 | 
             
                        end
         | 
| 417 438 | 
             
                      end
         | 
| 418 439 | 
             
                    end
         | 
| @@ -436,13 +457,13 @@ module ActiveRecord | |
| 436 457 | 
             
                      if autosave && record.marked_for_destruction?
         | 
| 437 458 | 
             
                        record.destroy
         | 
| 438 459 | 
             
                      elsif autosave != false
         | 
| 439 | 
            -
                        key = reflection.options[:primary_key] ?  | 
| 460 | 
            +
                        key = reflection.options[:primary_key] ? public_send(reflection.options[:primary_key]) : id
         | 
| 440 461 |  | 
| 441 | 
            -
                        if (autosave && record.changed_for_autosave?) ||  | 
| 462 | 
            +
                        if (autosave && record.changed_for_autosave?) || record_changed?(reflection, record, key)
         | 
| 442 463 | 
             
                          unless reflection.through_reflection
         | 
| 443 464 | 
             
                            record[reflection.foreign_key] = key
         | 
| 444 465 | 
             
                            if inverse_reflection = reflection.inverse_of
         | 
| 445 | 
            -
                              record.association(inverse_reflection.name). | 
| 466 | 
            +
                              record.association(inverse_reflection.name).inversed_from(self)
         | 
| 446 467 | 
             
                            end
         | 
| 447 468 | 
             
                          end
         | 
| 448 469 |  | 
| @@ -457,10 +478,16 @@ module ActiveRecord | |
| 457 478 | 
             
                  # If the record is new or it has changed, returns true.
         | 
| 458 479 | 
             
                  def record_changed?(reflection, record, key)
         | 
| 459 480 | 
             
                    record.new_record? ||
         | 
| 460 | 
            -
                       | 
| 481 | 
            +
                      association_foreign_key_changed?(reflection, record, key) ||
         | 
| 461 482 | 
             
                      record.will_save_change_to_attribute?(reflection.foreign_key)
         | 
| 462 483 | 
             
                  end
         | 
| 463 484 |  | 
| 485 | 
            +
                  def association_foreign_key_changed?(reflection, record, key)
         | 
| 486 | 
            +
                    return false if reflection.through_reflection?
         | 
| 487 | 
            +
             | 
| 488 | 
            +
                    record._has_attribute?(reflection.foreign_key) && record._read_attribute(reflection.foreign_key) != key
         | 
| 489 | 
            +
                  end
         | 
| 490 | 
            +
             | 
| 464 491 | 
             
                  # Saves the associated record if it's new or <tt>:autosave</tt> is enabled.
         | 
| 465 492 | 
             
                  #
         | 
| 466 493 | 
             
                  # In addition, it will destroy the association if it was marked for destruction.
         | 
| @@ -479,7 +506,7 @@ module ActiveRecord | |
| 479 506 | 
             
                        saved = record.save(validate: !autosave) if record.new_record? || (autosave && record.changed_for_autosave?)
         | 
| 480 507 |  | 
| 481 508 | 
             
                        if association.updated?
         | 
| 482 | 
            -
                          association_id = record. | 
| 509 | 
            +
                          association_id = record.public_send(reflection.options[:primary_key] || :id)
         | 
| 483 510 | 
             
                          self[reflection.foreign_key] = association_id
         | 
| 484 511 | 
             
                          association.loaded!
         | 
| 485 512 | 
             
                        end
         | 
| @@ -489,10 +516,12 @@ module ActiveRecord | |
| 489 516 | 
             
                    end
         | 
| 490 517 | 
             
                  end
         | 
| 491 518 |  | 
| 519 | 
            +
                  def custom_validation_context?
         | 
| 520 | 
            +
                    validation_context && [:create, :update].exclude?(validation_context)
         | 
| 521 | 
            +
                  end
         | 
| 522 | 
            +
             | 
| 492 523 | 
             
                  def _ensure_no_duplicate_errors
         | 
| 493 | 
            -
                    errors. | 
| 494 | 
            -
                      errors[attribute].uniq!
         | 
| 495 | 
            -
                    end
         | 
| 524 | 
            +
                    errors.uniq!
         | 
| 496 525 | 
             
                  end
         | 
| 497 526 | 
             
              end
         | 
| 498 527 | 
             
            end
         | 
    
        data/lib/active_record/base.rb
    CHANGED
    
    | @@ -1,28 +1,16 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require "yaml"
         | 
| 4 3 | 
             
            require "active_support/benchmarkable"
         | 
| 5 4 | 
             
            require "active_support/dependencies"
         | 
| 6 5 | 
             
            require "active_support/descendants_tracker"
         | 
| 7 6 | 
             
            require "active_support/time"
         | 
| 8 | 
            -
            require "active_support/core_ext/module/attribute_accessors"
         | 
| 9 | 
            -
            require "active_support/core_ext/array/extract_options"
         | 
| 10 | 
            -
            require "active_support/core_ext/hash/deep_merge"
         | 
| 11 | 
            -
            require "active_support/core_ext/hash/slice"
         | 
| 12 | 
            -
            require "active_support/core_ext/hash/transform_values"
         | 
| 13 | 
            -
            require "active_support/core_ext/string/behavior"
         | 
| 14 | 
            -
            require "active_support/core_ext/kernel/singleton_class"
         | 
| 15 | 
            -
            require "active_support/core_ext/module/introspection"
         | 
| 16 | 
            -
            require "active_support/core_ext/object/duplicable"
         | 
| 17 7 | 
             
            require "active_support/core_ext/class/subclasses"
         | 
| 18 | 
            -
            require "active_record/attribute_decorators"
         | 
| 19 | 
            -
            require "active_record/define_callbacks"
         | 
| 20 | 
            -
            require "active_record/errors"
         | 
| 21 8 | 
             
            require "active_record/log_subscriber"
         | 
| 22 9 | 
             
            require "active_record/explain_subscriber"
         | 
| 23 10 | 
             
            require "active_record/relation/delegation"
         | 
| 24 11 | 
             
            require "active_record/attributes"
         | 
| 25 12 | 
             
            require "active_record/type_caster"
         | 
| 13 | 
            +
            require "active_record/database_configurations"
         | 
| 26 14 |  | 
| 27 15 | 
             
            module ActiveRecord #:nodoc:
         | 
| 28 16 | 
             
              # = Active Record
         | 
| @@ -285,10 +273,11 @@ module ActiveRecord #:nodoc: | |
| 285 273 | 
             
                extend Querying
         | 
| 286 274 | 
             
                extend Translation
         | 
| 287 275 | 
             
                extend DynamicMatchers
         | 
| 276 | 
            +
                extend DelegatedType
         | 
| 288 277 | 
             
                extend Explain
         | 
| 289 278 | 
             
                extend Enum
         | 
| 290 279 | 
             
                extend Delegation::DelegateCache
         | 
| 291 | 
            -
                extend  | 
| 280 | 
            +
                extend Aggregations::ClassMethods
         | 
| 292 281 |  | 
| 293 282 | 
             
                include Core
         | 
| 294 283 | 
             
                include Persistence
         | 
| @@ -303,10 +292,8 @@ module ActiveRecord #:nodoc: | |
| 303 292 | 
             
                include Validations
         | 
| 304 293 | 
             
                include CounterCache
         | 
| 305 294 | 
             
                include Attributes
         | 
| 306 | 
            -
                include AttributeDecorators
         | 
| 307 295 | 
             
                include Locking::Optimistic
         | 
| 308 296 | 
             
                include Locking::Pessimistic
         | 
| 309 | 
            -
                include DefineCallbacks
         | 
| 310 297 | 
             
                include AttributeMethods
         | 
| 311 298 | 
             
                include Callbacks
         | 
| 312 299 | 
             
                include Timestamp
         | 
| @@ -314,7 +301,6 @@ module ActiveRecord #:nodoc: | |
| 314 301 | 
             
                include ActiveModel::SecurePassword
         | 
| 315 302 | 
             
                include AutosaveAssociation
         | 
| 316 303 | 
             
                include NestedAttributes
         | 
| 317 | 
            -
                include Aggregations
         | 
| 318 304 | 
             
                include Transactions
         | 
| 319 305 | 
             
                include TouchLater
         | 
| 320 306 | 
             
                include NoTouching
         | 
| @@ -322,6 +308,7 @@ module ActiveRecord #:nodoc: | |
| 322 308 | 
             
                include Serialization
         | 
| 323 309 | 
             
                include Store
         | 
| 324 310 | 
             
                include SecureToken
         | 
| 311 | 
            +
                include SignedId
         | 
| 325 312 | 
             
                include Suppressor
         | 
| 326 313 | 
             
              end
         | 
| 327 314 |  | 
| @@ -4,7 +4,7 @@ module ActiveRecord | |
| 4 4 | 
             
              # = Active Record \Callbacks
         | 
| 5 5 | 
             
              #
         | 
| 6 6 | 
             
              # \Callbacks are hooks into the life cycle of an Active Record object that allow you to trigger logic
         | 
| 7 | 
            -
              # before or after  | 
| 7 | 
            +
              # before or after a change in the object state. This can be used to make sure that associated and
         | 
| 8 8 | 
             
              # dependent objects are deleted when {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] is called (by overwriting +before_destroy+) or
         | 
| 9 9 | 
             
              # to massage attributes before they're validated (by overwriting +before_validation+).
         | 
| 10 10 | 
             
              # As an example of the callbacks initiated, consider the {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] call for a new record:
         | 
| @@ -32,7 +32,7 @@ module ActiveRecord | |
| 32 32 | 
             
              # is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
         | 
| 33 33 | 
             
              # are instantiated as well.
         | 
| 34 34 | 
             
              #
         | 
| 35 | 
            -
              # There are nineteen callbacks in total, which give  | 
| 35 | 
            +
              # There are nineteen callbacks in total, which give a lot of control over how to react and prepare for each state in the
         | 
| 36 36 | 
             
              # Active Record life cycle. The sequence for calling {ActiveRecord::Base#save}[rdoc-ref:Persistence#save] for an existing record is similar,
         | 
| 37 37 | 
             
              # except that each <tt>_create</tt> callback is replaced by the corresponding <tt>_update</tt> callback.
         | 
| 38 38 | 
             
              #
         | 
| @@ -64,7 +64,7 @@ module ActiveRecord | |
| 64 64 | 
             
              #
         | 
| 65 65 | 
             
              # Besides the overwritable callback methods, it's also possible to register callbacks through the
         | 
| 66 66 | 
             
              # use of the callback macros. Their main advantage is that the macros add behavior into a callback
         | 
| 67 | 
            -
              # queue that is kept intact  | 
| 67 | 
            +
              # queue that is kept intact through an inheritance hierarchy.
         | 
| 68 68 | 
             
              #
         | 
| 69 69 | 
             
              #   class Topic < ActiveRecord::Base
         | 
| 70 70 | 
             
              #     before_destroy :destroy_author
         | 
| @@ -74,22 +74,8 @@ module ActiveRecord | |
| 74 74 | 
             
              #     before_destroy :destroy_readers
         | 
| 75 75 | 
             
              #   end
         | 
| 76 76 | 
             
              #
         | 
| 77 | 
            -
              #  | 
| 78 | 
            -
              # run, both +destroy_author+ and +destroy_readers+ are called. | 
| 79 | 
            -
              # where the +before_destroy+ method is overridden:
         | 
| 80 | 
            -
              #
         | 
| 81 | 
            -
              #   class Topic < ActiveRecord::Base
         | 
| 82 | 
            -
              #     def before_destroy() destroy_author end
         | 
| 83 | 
            -
              #   end
         | 
| 84 | 
            -
              #
         | 
| 85 | 
            -
              #   class Reply < Topic
         | 
| 86 | 
            -
              #     def before_destroy() destroy_readers end
         | 
| 87 | 
            -
              #   end
         | 
| 88 | 
            -
              #
         | 
| 89 | 
            -
              # In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+.
         | 
| 90 | 
            -
              # So, use the callback macros when you want to ensure that a certain callback is called for the entire
         | 
| 91 | 
            -
              # hierarchy, and use the regular overwritable methods when you want to leave it up to each descendant
         | 
| 92 | 
            -
              # to decide whether they want to call +super+ and trigger the inherited callbacks.
         | 
| 77 | 
            +
              # When <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is
         | 
| 78 | 
            +
              # run, both +destroy_author+ and +destroy_readers+ are called.
         | 
| 93 79 | 
             
              #
         | 
| 94 80 | 
             
              # *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the
         | 
| 95 81 | 
             
              # callbacks before specifying the associations. Otherwise, you might trigger the loading of a
         | 
| @@ -97,10 +83,9 @@ module ActiveRecord | |
| 97 83 | 
             
              #
         | 
| 98 84 | 
             
              # == Types of callbacks
         | 
| 99 85 | 
             
              #
         | 
| 100 | 
            -
              # There are  | 
| 101 | 
            -
              # inline methods (using a proc). Method references and callback objects
         | 
| 102 | 
            -
              #  | 
| 103 | 
            -
              # creating mix-ins).
         | 
| 86 | 
            +
              # There are three types of callbacks accepted by the callback macros: method references (symbol), callback objects,
         | 
| 87 | 
            +
              # inline methods (using a proc). Method references and callback objects are the recommended approaches,
         | 
| 88 | 
            +
              # inline methods using a proc are sometimes appropriate (such as for creating mix-ins).
         | 
| 104 89 | 
             
              #
         | 
| 105 90 | 
             
              # The method reference callbacks work by specifying a protected or private method available in the object, like this:
         | 
| 106 91 | 
             
              #
         | 
| @@ -109,7 +94,7 @@ module ActiveRecord | |
| 109 94 | 
             
              #
         | 
| 110 95 | 
             
              #     private
         | 
| 111 96 | 
             
              #       def delete_parents
         | 
| 112 | 
            -
              #         self.class. | 
| 97 | 
            +
              #         self.class.delete_by(parent_id: id)
         | 
| 113 98 | 
             
              #       end
         | 
| 114 99 | 
             
              #   end
         | 
| 115 100 | 
             
              #
         | 
| @@ -142,7 +127,7 @@ module ActiveRecord | |
| 142 127 | 
             
              #       end
         | 
| 143 128 | 
             
              #   end
         | 
| 144 129 | 
             
              #
         | 
| 145 | 
            -
              # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
         | 
| 130 | 
            +
              # So you specify the object you want to be messaged on a given callback. When that callback is triggered, the object has
         | 
| 146 131 | 
             
              # a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other
         | 
| 147 132 | 
             
              # initialization data such as the name of the attribute to work with:
         | 
| 148 133 | 
             
              #
         | 
| @@ -193,8 +178,8 @@ module ActiveRecord | |
| 193 178 | 
             
              #
         | 
| 194 179 | 
             
              # == Ordering callbacks
         | 
| 195 180 | 
             
              #
         | 
| 196 | 
            -
              # Sometimes  | 
| 197 | 
            -
              # callback (+log_children+ in this case) should be executed before the children  | 
| 181 | 
            +
              # Sometimes application code requires that callbacks execute in a specific order. For example, a +before_destroy+
         | 
| 182 | 
            +
              # callback (+log_children+ in this case) should be executed before records in the +children+ association are destroyed by the
         | 
| 198 183 | 
             
              # <tt>dependent: :destroy</tt> option.
         | 
| 199 184 | 
             
              #
         | 
| 200 185 | 
             
              # Let's look at the code below:
         | 
| @@ -210,8 +195,8 @@ module ActiveRecord | |
| 210 195 | 
             
              #       end
         | 
| 211 196 | 
             
              #   end
         | 
| 212 197 | 
             
              #
         | 
| 213 | 
            -
              # In this case, the problem is that when the +before_destroy+ callback is executed, the children  | 
| 214 | 
            -
              # because the {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] callback  | 
| 198 | 
            +
              # In this case, the problem is that when the +before_destroy+ callback is executed, records in the +children+ association no
         | 
| 199 | 
            +
              # longer exist because the {ActiveRecord::Base#destroy}[rdoc-ref:Persistence#destroy] callback was executed first.
         | 
| 215 200 | 
             
              # You can use the +prepend+ option on the +before_destroy+ callback to avoid this.
         | 
| 216 201 | 
             
              #
         | 
| 217 202 | 
             
              #   class Topic < ActiveRecord::Base
         | 
| @@ -225,7 +210,7 @@ module ActiveRecord | |
| 225 210 | 
             
              #       end
         | 
| 226 211 | 
             
              #   end
         | 
| 227 212 | 
             
              #
         | 
| 228 | 
            -
              # This way, the +before_destroy+  | 
| 213 | 
            +
              # This way, the +before_destroy+ is executed before the <tt>dependent: :destroy</tt> is called, and the data is still available.
         | 
| 229 214 | 
             
              #
         | 
| 230 215 | 
             
              # Also, there are cases when you want several callbacks of the same type to
         | 
| 231 216 | 
             
              # be executed in order.
         | 
| @@ -249,10 +234,10 @@ module ActiveRecord | |
| 249 234 | 
             
              #     end
         | 
| 250 235 | 
             
              #   end
         | 
| 251 236 | 
             
              #
         | 
| 252 | 
            -
              # In this case the +log_children+  | 
| 237 | 
            +
              # In this case the +log_children+ is executed before +do_something_else+.
         | 
| 253 238 | 
             
              # The same applies to all non-transactional callbacks.
         | 
| 254 239 | 
             
              #
         | 
| 255 | 
            -
              #  | 
| 240 | 
            +
              # As seen below, in case there are multiple transactional callbacks the order
         | 
| 256 241 | 
             
              # is reversed.
         | 
| 257 242 | 
             
              #
         | 
| 258 243 | 
             
              # For example:
         | 
| @@ -274,16 +259,16 @@ module ActiveRecord | |
| 274 259 | 
             
              #     end
         | 
| 275 260 | 
             
              #   end
         | 
| 276 261 | 
             
              #
         | 
| 277 | 
            -
              # In this case the +do_something_else+  | 
| 262 | 
            +
              # In this case the +do_something_else+ is executed before +log_children+.
         | 
| 278 263 | 
             
              #
         | 
| 279 264 | 
             
              # == \Transactions
         | 
| 280 265 | 
             
              #
         | 
| 281 266 | 
             
              # The entire callback chain of a {#save}[rdoc-ref:Persistence#save], {#save!}[rdoc-ref:Persistence#save!],
         | 
| 282 267 | 
             
              # or {#destroy}[rdoc-ref:Persistence#destroy] call runs within a transaction. That includes <tt>after_*</tt> hooks.
         | 
| 283 | 
            -
              # If everything goes fine a COMMIT is executed once the chain has been completed.
         | 
| 268 | 
            +
              # If everything goes fine a +COMMIT+ is executed once the chain has been completed.
         | 
| 284 269 | 
             
              #
         | 
| 285 | 
            -
              # If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
         | 
| 286 | 
            -
              # can also trigger a ROLLBACK raising an exception in any of the callbacks,
         | 
| 270 | 
            +
              # If a <tt>before_*</tt> callback cancels the action a +ROLLBACK+ is issued. You
         | 
| 271 | 
            +
              # can also trigger a +ROLLBACK+ raising an exception in any of the callbacks,
         | 
| 287 272 | 
             
              # including <tt>after_*</tt> hooks. Note, however, that in that case the client
         | 
| 288 273 | 
             
              # needs to be aware of it because an ordinary {#save}[rdoc-ref:Persistence#save] will raise such exception
         | 
| 289 274 | 
             
              # instead of quietly returning +false+.
         | 
| @@ -294,17 +279,17 @@ module ActiveRecord | |
| 294 279 | 
             
              # <tt>:before</tt>, <tt>:after</tt> and <tt>:around</tt> as values for the <tt>kind</tt> property. The <tt>kind</tt> property
         | 
| 295 280 | 
             
              # defines what part of the chain the callback runs in.
         | 
| 296 281 | 
             
              #
         | 
| 297 | 
            -
              # To find all callbacks in the before_save callback chain:
         | 
| 282 | 
            +
              # To find all callbacks in the +before_save+ callback chain:
         | 
| 298 283 | 
             
              #
         | 
| 299 284 | 
             
              #   Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
         | 
| 300 285 | 
             
              #
         | 
| 301 | 
            -
              # Returns an array of callback objects that form the before_save chain.
         | 
| 286 | 
            +
              # Returns an array of callback objects that form the +before_save+ chain.
         | 
| 302 287 | 
             
              #
         | 
| 303 288 | 
             
              # To further check if the before_save chain contains a proc defined as <tt>rest_when_dead</tt> use the <tt>filter</tt> property of the callback object:
         | 
| 304 289 | 
             
              #
         | 
| 305 290 | 
             
              #   Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }.collect(&:filter).include?(:rest_when_dead)
         | 
| 306 291 | 
             
              #
         | 
| 307 | 
            -
              # Returns true or false depending on whether the proc is contained in the before_save callback chain on a Topic model.
         | 
| 292 | 
            +
              # Returns true or false depending on whether the proc is contained in the +before_save+ callback chain on a Topic model.
         | 
| 308 293 | 
             
              #
         | 
| 309 294 | 
             
              module Callbacks
         | 
| 310 295 | 
             
                extend ActiveSupport::Concern
         | 
| @@ -316,6 +301,137 @@ module ActiveRecord | |
| 316 301 | 
             
                  :before_destroy, :around_destroy, :after_destroy, :after_commit, :after_rollback
         | 
| 317 302 | 
             
                ]
         | 
| 318 303 |  | 
| 304 | 
            +
                module ClassMethods
         | 
| 305 | 
            +
                  include ActiveModel::Callbacks
         | 
| 306 | 
            +
             | 
| 307 | 
            +
                  ##
         | 
| 308 | 
            +
                  # :method: after_initialize
         | 
| 309 | 
            +
                  #
         | 
| 310 | 
            +
                  # :call-seq: after_initialize(*args, &block)
         | 
| 311 | 
            +
                  #
         | 
| 312 | 
            +
                  # Registers a callback to be called after a record is instantiated. See
         | 
| 313 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 314 | 
            +
             | 
| 315 | 
            +
                  ##
         | 
| 316 | 
            +
                  # :method: after_find
         | 
| 317 | 
            +
                  #
         | 
| 318 | 
            +
                  # :call-seq: after_find(*args, &block)
         | 
| 319 | 
            +
                  #
         | 
| 320 | 
            +
                  # Registers a callback to be called after a record is instantiated
         | 
| 321 | 
            +
                  # via a finder. See ActiveRecord::Callbacks for more information.
         | 
| 322 | 
            +
             | 
| 323 | 
            +
                  ##
         | 
| 324 | 
            +
                  # :method: after_touch
         | 
| 325 | 
            +
                  #
         | 
| 326 | 
            +
                  # :call-seq: after_touch(*args, &block)
         | 
| 327 | 
            +
                  #
         | 
| 328 | 
            +
                  # Registers a callback to be called after a record is touched. See
         | 
| 329 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 330 | 
            +
             | 
| 331 | 
            +
                  ##
         | 
| 332 | 
            +
                  # :method: before_save
         | 
| 333 | 
            +
                  #
         | 
| 334 | 
            +
                  # :call-seq: before_save(*args, &block)
         | 
| 335 | 
            +
                  #
         | 
| 336 | 
            +
                  # Registers a callback to be called before a record is saved. See
         | 
| 337 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 338 | 
            +
             | 
| 339 | 
            +
                  ##
         | 
| 340 | 
            +
                  # :method: around_save
         | 
| 341 | 
            +
                  #
         | 
| 342 | 
            +
                  # :call-seq: around_save(*args, &block)
         | 
| 343 | 
            +
                  #
         | 
| 344 | 
            +
                  # Registers a callback to be called around the save of a record. See
         | 
| 345 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 346 | 
            +
             | 
| 347 | 
            +
                  ##
         | 
| 348 | 
            +
                  # :method: after_save
         | 
| 349 | 
            +
                  #
         | 
| 350 | 
            +
                  # :call-seq: after_save(*args, &block)
         | 
| 351 | 
            +
                  #
         | 
| 352 | 
            +
                  # Registers a callback to be called after a record is saved. See
         | 
| 353 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 354 | 
            +
             | 
| 355 | 
            +
                  ##
         | 
| 356 | 
            +
                  # :method: before_create
         | 
| 357 | 
            +
                  #
         | 
| 358 | 
            +
                  # :call-seq: before_create(*args, &block)
         | 
| 359 | 
            +
                  #
         | 
| 360 | 
            +
                  # Registers a callback to be called before a record is created. See
         | 
| 361 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 362 | 
            +
             | 
| 363 | 
            +
                  ##
         | 
| 364 | 
            +
                  # :method: around_create
         | 
| 365 | 
            +
                  #
         | 
| 366 | 
            +
                  # :call-seq: around_create(*args, &block)
         | 
| 367 | 
            +
                  #
         | 
| 368 | 
            +
                  # Registers a callback to be called around the creation of a record. See
         | 
| 369 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 370 | 
            +
             | 
| 371 | 
            +
                  ##
         | 
| 372 | 
            +
                  # :method: after_create
         | 
| 373 | 
            +
                  #
         | 
| 374 | 
            +
                  # :call-seq: after_create(*args, &block)
         | 
| 375 | 
            +
                  #
         | 
| 376 | 
            +
                  # Registers a callback to be called after a record is created. See
         | 
| 377 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 378 | 
            +
             | 
| 379 | 
            +
                  ##
         | 
| 380 | 
            +
                  # :method: before_update
         | 
| 381 | 
            +
                  #
         | 
| 382 | 
            +
                  # :call-seq: before_update(*args, &block)
         | 
| 383 | 
            +
                  #
         | 
| 384 | 
            +
                  # Registers a callback to be called before a record is updated. See
         | 
| 385 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 386 | 
            +
             | 
| 387 | 
            +
                  ##
         | 
| 388 | 
            +
                  # :method: around_update
         | 
| 389 | 
            +
                  #
         | 
| 390 | 
            +
                  # :call-seq: around_update(*args, &block)
         | 
| 391 | 
            +
                  #
         | 
| 392 | 
            +
                  # Registers a callback to be called around the update of a record. See
         | 
| 393 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 394 | 
            +
             | 
| 395 | 
            +
                  ##
         | 
| 396 | 
            +
                  # :method: after_update
         | 
| 397 | 
            +
                  #
         | 
| 398 | 
            +
                  # :call-seq: after_update(*args, &block)
         | 
| 399 | 
            +
                  #
         | 
| 400 | 
            +
                  # Registers a callback to be called after a record is updated. See
         | 
| 401 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 402 | 
            +
             | 
| 403 | 
            +
                  ##
         | 
| 404 | 
            +
                  # :method: before_destroy
         | 
| 405 | 
            +
                  #
         | 
| 406 | 
            +
                  # :call-seq: before_destroy(*args, &block)
         | 
| 407 | 
            +
                  #
         | 
| 408 | 
            +
                  # Registers a callback to be called before a record is destroyed. See
         | 
| 409 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 410 | 
            +
             | 
| 411 | 
            +
                  ##
         | 
| 412 | 
            +
                  # :method: around_destroy
         | 
| 413 | 
            +
                  #
         | 
| 414 | 
            +
                  # :call-seq: around_destroy(*args, &block)
         | 
| 415 | 
            +
                  #
         | 
| 416 | 
            +
                  # Registers a callback to be called around the destruction of a record.
         | 
| 417 | 
            +
                  # See ActiveRecord::Callbacks for more information.
         | 
| 418 | 
            +
             | 
| 419 | 
            +
                  ##
         | 
| 420 | 
            +
                  # :method: after_destroy
         | 
| 421 | 
            +
                  #
         | 
| 422 | 
            +
                  # :call-seq: after_destroy(*args, &block)
         | 
| 423 | 
            +
                  #
         | 
| 424 | 
            +
                  # Registers a callback to be called after a record is destroyed. See
         | 
| 425 | 
            +
                  # ActiveRecord::Callbacks for more information.
         | 
| 426 | 
            +
                end
         | 
| 427 | 
            +
             | 
| 428 | 
            +
                included do
         | 
| 429 | 
            +
                  include ActiveModel::Validations::Callbacks
         | 
| 430 | 
            +
             | 
| 431 | 
            +
                  define_model_callbacks :initialize, :find, :touch, only: :after
         | 
| 432 | 
            +
                  define_model_callbacks :save, :create, :update, :destroy
         | 
| 433 | 
            +
                end
         | 
| 434 | 
            +
             | 
| 319 435 | 
             
                def destroy #:nodoc:
         | 
| 320 436 | 
             
                  @_destroy_callback_already_called ||= false
         | 
| 321 437 | 
             
                  return if @_destroy_callback_already_called
         | 
| @@ -328,7 +444,7 @@ module ActiveRecord | |
| 328 444 | 
             
                  @_destroy_callback_already_called = false
         | 
| 329 445 | 
             
                end
         | 
| 330 446 |  | 
| 331 | 
            -
                def touch( | 
| 447 | 
            +
                def touch(*, **) #:nodoc:
         | 
| 332 448 | 
             
                  _run_touch_callbacks { super }
         | 
| 333 449 | 
             
                end
         | 
| 334 450 |  | 
| @@ -337,8 +453,7 @@ module ActiveRecord | |
| 337 453 | 
             
                end
         | 
| 338 454 |  | 
| 339 455 | 
             
              private
         | 
| 340 | 
            -
             | 
| 341 | 
            -
                def create_or_update(*)
         | 
| 456 | 
            +
                def create_or_update(**)
         | 
| 342 457 | 
             
                  _run_save_callbacks { super }
         | 
| 343 458 | 
             
                end
         | 
| 344 459 |  | 
| @@ -346,7 +461,7 @@ module ActiveRecord | |
| 346 461 | 
             
                  _run_create_callbacks { super }
         | 
| 347 462 | 
             
                end
         | 
| 348 463 |  | 
| 349 | 
            -
                def _update_record | 
| 464 | 
            +
                def _update_record
         | 
| 350 465 | 
             
                  _run_update_callbacks { super }
         | 
| 351 466 | 
             
                end
         | 
| 352 467 | 
             
              end
         |