activerecord 6.1.7 → 7.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +520 -1385
- data/MIT-LICENSE +1 -1
- data/README.rdoc +31 -31
- data/examples/performance.rb +2 -2
- data/lib/active_record/aggregations.rb +17 -14
- data/lib/active_record/association_relation.rb +2 -12
- data/lib/active_record/associations/alias_tracker.rb +25 -19
- data/lib/active_record/associations/association.rb +60 -21
- data/lib/active_record/associations/association_scope.rb +17 -12
- data/lib/active_record/associations/belongs_to_association.rb +37 -11
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +13 -4
- data/lib/active_record/associations/builder/association.rb +11 -5
- data/lib/active_record/associations/builder/belongs_to.rb +41 -14
- data/lib/active_record/associations/builder/collection_association.rb +10 -3
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -7
- data/lib/active_record/associations/builder/has_many.rb +4 -4
- data/lib/active_record/associations/builder/has_one.rb +4 -4
- data/lib/active_record/associations/builder/singular_association.rb +6 -2
- data/lib/active_record/associations/collection_association.rb +46 -36
- data/lib/active_record/associations/collection_proxy.rb +44 -16
- data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
- data/lib/active_record/associations/errors.rb +265 -0
- data/lib/active_record/associations/foreign_association.rb +10 -3
- data/lib/active_record/associations/has_many_association.rb +29 -19
- data/lib/active_record/associations/has_many_through_association.rb +12 -7
- data/lib/active_record/associations/has_one_association.rb +20 -10
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
- data/lib/active_record/associations/join_dependency.rb +23 -15
- data/lib/active_record/associations/nested_error.rb +47 -0
- data/lib/active_record/associations/preloader/association.rb +212 -53
- data/lib/active_record/associations/preloader/batch.rb +48 -0
- data/lib/active_record/associations/preloader/branch.rb +153 -0
- data/lib/active_record/associations/preloader/through_association.rb +50 -16
- data/lib/active_record/associations/preloader.rb +50 -121
- data/lib/active_record/associations/singular_association.rb +15 -3
- data/lib/active_record/associations/through_association.rb +25 -14
- data/lib/active_record/associations.rb +404 -509
- data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
- data/lib/active_record/attribute_assignment.rb +2 -14
- data/lib/active_record/attribute_methods/before_type_cast.rb +24 -2
- data/lib/active_record/attribute_methods/composite_primary_key.rb +84 -0
- data/lib/active_record/attribute_methods/dirty.rb +73 -22
- data/lib/active_record/attribute_methods/primary_key.rb +47 -27
- data/lib/active_record/attribute_methods/query.rb +31 -19
- data/lib/active_record/attribute_methods/read.rb +14 -11
- data/lib/active_record/attribute_methods/serialization.rb +174 -37
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -9
- data/lib/active_record/attribute_methods/write.rb +12 -15
- data/lib/active_record/attribute_methods.rb +164 -52
- data/lib/active_record/attributes.rb +51 -49
- data/lib/active_record/autosave_association.rb +74 -57
- data/lib/active_record/base.rb +27 -5
- data/lib/active_record/callbacks.rb +18 -34
- data/lib/active_record/coders/column_serializer.rb +61 -0
- data/lib/active_record/coders/json.rb +1 -1
- data/lib/active_record/coders/yaml_column.rb +70 -46
- data/lib/active_record/connection_adapters/abstract/connection_handler.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +211 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +79 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +327 -612
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -17
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -60
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +201 -64
- data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -131
- data/lib/active_record/connection_adapters/abstract/savepoints.rb +4 -3
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +21 -20
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +186 -31
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +14 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +377 -142
- data/lib/active_record/connection_adapters/abstract/transaction.rb +361 -76
- data/lib/active_record/connection_adapters/abstract_adapter.rb +624 -163
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +345 -166
- data/lib/active_record/connection_adapters/column.rb +13 -0
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -0
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +29 -130
- data/lib/active_record/connection_adapters/mysql/quoting.rb +81 -55
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +9 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +10 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +8 -2
- data/lib/active_record/connection_adapters/mysql/schema_statements.rb +45 -14
- data/lib/active_record/connection_adapters/mysql2/database_statements.rb +152 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +107 -68
- data/lib/active_record/connection_adapters/pool_config.rb +26 -16
- data/lib/active_record/connection_adapters/pool_manager.rb +19 -9
- data/lib/active_record/connection_adapters/postgresql/column.rb +30 -1
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +114 -54
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +6 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
- data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +12 -3
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +14 -4
- data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +137 -104
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +92 -2
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +173 -3
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +78 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +401 -77
- data/lib/active_record/connection_adapters/postgresql/utils.rb +9 -10
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +518 -251
- data/lib/active_record/connection_adapters/schema_cache.rb +326 -102
- data/lib/active_record/connection_adapters/sqlite3/column.rb +62 -0
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +78 -55
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +68 -54
- data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +20 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +16 -0
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +66 -22
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +372 -130
- data/lib/active_record/connection_adapters/statement_pool.rb +7 -0
- data/lib/active_record/connection_adapters/trilogy/database_statements.rb +99 -0
- data/lib/active_record/connection_adapters/trilogy_adapter.rb +229 -0
- data/lib/active_record/connection_adapters.rb +130 -6
- data/lib/active_record/connection_handling.rb +132 -146
- data/lib/active_record/core.rb +276 -251
- data/lib/active_record/counter_cache.rb +68 -34
- data/lib/active_record/database_configurations/connection_url_resolver.rb +9 -3
- data/lib/active_record/database_configurations/database_config.rb +34 -10
- data/lib/active_record/database_configurations/hash_config.rb +107 -31
- data/lib/active_record/database_configurations/url_config.rb +38 -13
- data/lib/active_record/database_configurations.rb +96 -60
- data/lib/active_record/delegated_type.rb +90 -20
- data/lib/active_record/deprecator.rb +7 -0
- data/lib/active_record/destroy_association_async_job.rb +4 -2
- data/lib/active_record/disable_joins_association_relation.rb +39 -0
- data/lib/active_record/dynamic_matchers.rb +3 -3
- data/lib/active_record/encryption/auto_filtered_parameters.rb +66 -0
- data/lib/active_record/encryption/cipher/aes256_gcm.rb +101 -0
- data/lib/active_record/encryption/cipher.rb +53 -0
- data/lib/active_record/encryption/config.rb +68 -0
- data/lib/active_record/encryption/configurable.rb +60 -0
- data/lib/active_record/encryption/context.rb +42 -0
- data/lib/active_record/encryption/contexts.rb +76 -0
- data/lib/active_record/encryption/derived_secret_key_provider.rb +18 -0
- data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
- data/lib/active_record/encryption/encryptable_record.rb +230 -0
- data/lib/active_record/encryption/encrypted_attribute_type.rb +175 -0
- data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
- data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
- data/lib/active_record/encryption/encryptor.rb +170 -0
- data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
- data/lib/active_record/encryption/errors.rb +15 -0
- data/lib/active_record/encryption/extended_deterministic_queries.rb +157 -0
- data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
- data/lib/active_record/encryption/key.rb +28 -0
- data/lib/active_record/encryption/key_generator.rb +53 -0
- data/lib/active_record/encryption/key_provider.rb +46 -0
- data/lib/active_record/encryption/message.rb +33 -0
- data/lib/active_record/encryption/message_pack_message_serializer.rb +76 -0
- data/lib/active_record/encryption/message_serializer.rb +96 -0
- data/lib/active_record/encryption/null_encryptor.rb +25 -0
- data/lib/active_record/encryption/properties.rb +76 -0
- data/lib/active_record/encryption/read_only_null_encryptor.rb +28 -0
- data/lib/active_record/encryption/scheme.rb +100 -0
- data/lib/active_record/encryption.rb +56 -0
- data/lib/active_record/enum.rb +163 -63
- data/lib/active_record/errors.rb +210 -27
- data/lib/active_record/explain.rb +21 -12
- data/lib/active_record/explain_registry.rb +11 -6
- data/lib/active_record/explain_subscriber.rb +1 -1
- data/lib/active_record/fixture_set/file.rb +15 -1
- data/lib/active_record/fixture_set/model_metadata.rb +14 -4
- data/lib/active_record/fixture_set/render_context.rb +2 -0
- data/lib/active_record/fixture_set/table_row.rb +70 -14
- data/lib/active_record/fixture_set/table_rows.rb +4 -4
- data/lib/active_record/fixtures.rb +179 -112
- data/lib/active_record/future_result.rb +178 -0
- data/lib/active_record/gem_version.rb +4 -4
- data/lib/active_record/inheritance.rb +85 -31
- data/lib/active_record/insert_all.rb +148 -32
- data/lib/active_record/integration.rb +14 -10
- data/lib/active_record/internal_metadata.rb +123 -23
- data/lib/active_record/legacy_yaml_adapter.rb +2 -39
- data/lib/active_record/locking/optimistic.rb +43 -27
- data/lib/active_record/locking/pessimistic.rb +15 -6
- data/lib/active_record/log_subscriber.rb +41 -29
- data/lib/active_record/marshalling.rb +56 -0
- data/lib/active_record/message_pack.rb +124 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +10 -10
- data/lib/active_record/middleware/database_selector.rb +23 -13
- data/lib/active_record/middleware/shard_selector.rb +62 -0
- data/lib/active_record/migration/command_recorder.rb +113 -16
- data/lib/active_record/migration/compatibility.rb +235 -46
- data/lib/active_record/migration/default_strategy.rb +22 -0
- data/lib/active_record/migration/execution_strategy.rb +19 -0
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/migration/pending_migration_connection.rb +21 -0
- data/lib/active_record/migration.rb +374 -177
- data/lib/active_record/model_schema.rb +143 -159
- data/lib/active_record/nested_attributes.rb +48 -21
- data/lib/active_record/no_touching.rb +3 -3
- data/lib/active_record/normalization.rb +163 -0
- data/lib/active_record/persistence.rb +282 -283
- data/lib/active_record/promise.rb +84 -0
- data/lib/active_record/query_cache.rb +19 -25
- data/lib/active_record/query_logs.rb +189 -0
- data/lib/active_record/query_logs_formatter.rb +41 -0
- data/lib/active_record/querying.rb +44 -9
- data/lib/active_record/railtie.rb +234 -71
- data/lib/active_record/railties/controller_runtime.rb +25 -11
- data/lib/active_record/railties/databases.rake +189 -256
- data/lib/active_record/railties/job_runtime.rb +23 -0
- data/lib/active_record/readonly_attributes.rb +41 -3
- data/lib/active_record/reflection.rb +325 -103
- data/lib/active_record/relation/batches/batch_enumerator.rb +38 -9
- data/lib/active_record/relation/batches.rb +198 -63
- data/lib/active_record/relation/calculations.rb +300 -111
- data/lib/active_record/relation/delegation.rb +33 -22
- data/lib/active_record/relation/finder_methods.rb +123 -52
- data/lib/active_record/relation/merger.rb +26 -19
- data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +38 -4
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -7
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +5 -1
- data/lib/active_record/relation/predicate_builder.rb +29 -22
- data/lib/active_record/relation/query_attribute.rb +30 -12
- data/lib/active_record/relation/query_methods.rb +842 -150
- data/lib/active_record/relation/record_fetch_warning.rb +10 -9
- data/lib/active_record/relation/spawn_methods.rb +7 -6
- data/lib/active_record/relation/where_clause.rb +15 -36
- data/lib/active_record/relation.rb +736 -145
- data/lib/active_record/result.rb +67 -54
- data/lib/active_record/runtime_registry.rb +71 -13
- data/lib/active_record/sanitization.rb +84 -34
- data/lib/active_record/schema.rb +39 -23
- data/lib/active_record/schema_dumper.rb +90 -31
- data/lib/active_record/schema_migration.rb +74 -23
- data/lib/active_record/scoping/default.rb +72 -15
- data/lib/active_record/scoping/named.rb +5 -13
- data/lib/active_record/scoping.rb +65 -34
- data/lib/active_record/secure_password.rb +60 -0
- data/lib/active_record/secure_token.rb +21 -3
- data/lib/active_record/serialization.rb +6 -1
- data/lib/active_record/signed_id.rb +30 -9
- data/lib/active_record/statement_cache.rb +7 -7
- data/lib/active_record/store.rb +10 -10
- data/lib/active_record/suppressor.rb +13 -15
- data/lib/active_record/table_metadata.rb +7 -3
- data/lib/active_record/tasks/database_tasks.rb +277 -149
- data/lib/active_record/tasks/mysql_database_tasks.rb +16 -7
- data/lib/active_record/tasks/postgresql_database_tasks.rb +35 -26
- data/lib/active_record/tasks/sqlite_database_tasks.rb +16 -7
- data/lib/active_record/test_databases.rb +1 -1
- data/lib/active_record/test_fixtures.rb +173 -155
- data/lib/active_record/testing/query_assertions.rb +121 -0
- data/lib/active_record/timestamp.rb +32 -19
- data/lib/active_record/token_for.rb +123 -0
- data/lib/active_record/touch_later.rb +12 -7
- data/lib/active_record/transaction.rb +132 -0
- data/lib/active_record/transactions.rb +118 -41
- data/lib/active_record/translation.rb +3 -5
- data/lib/active_record/type/adapter_specific_registry.rb +32 -14
- data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
- data/lib/active_record/type/internal/timezone.rb +7 -2
- data/lib/active_record/type/serialized.rb +9 -7
- data/lib/active_record/type/time.rb +4 -0
- data/lib/active_record/type/type_map.rb +17 -20
- data/lib/active_record/type.rb +1 -2
- data/lib/active_record/type_caster/connection.rb +4 -4
- data/lib/active_record/validations/absence.rb +1 -1
- data/lib/active_record/validations/associated.rb +13 -7
- data/lib/active_record/validations/numericality.rb +5 -4
- data/lib/active_record/validations/presence.rb +5 -28
- data/lib/active_record/validations/uniqueness.rb +64 -15
- data/lib/active_record/validations.rb +12 -5
- data/lib/active_record/version.rb +1 -1
- data/lib/active_record.rb +444 -32
- data/lib/arel/alias_predication.rb +1 -1
- data/lib/arel/attributes/attribute.rb +0 -8
- data/lib/arel/collectors/bind.rb +2 -0
- data/lib/arel/collectors/composite.rb +7 -0
- data/lib/arel/collectors/sql_string.rb +1 -1
- data/lib/arel/collectors/substitute_binds.rb +1 -1
- data/lib/arel/crud.rb +28 -22
- data/lib/arel/delete_manager.rb +18 -4
- data/lib/arel/errors.rb +10 -0
- data/lib/arel/factory_methods.rb +4 -0
- data/lib/arel/filter_predications.rb +9 -0
- data/lib/arel/insert_manager.rb +2 -3
- data/lib/arel/nodes/binary.rb +6 -7
- data/lib/arel/nodes/bound_sql_literal.rb +65 -0
- data/lib/arel/nodes/casted.rb +1 -1
- data/lib/arel/nodes/cte.rb +36 -0
- data/lib/arel/nodes/delete_statement.rb +12 -13
- data/lib/arel/nodes/filter.rb +10 -0
- data/lib/arel/nodes/fragments.rb +35 -0
- data/lib/arel/nodes/function.rb +1 -0
- data/lib/arel/nodes/homogeneous_in.rb +1 -9
- data/lib/arel/nodes/insert_statement.rb +2 -2
- data/lib/arel/nodes/leading_join.rb +8 -0
- data/lib/arel/nodes/{and.rb → nary.rb} +9 -2
- data/lib/arel/nodes/node.rb +115 -5
- data/lib/arel/nodes/select_core.rb +2 -2
- data/lib/arel/nodes/select_statement.rb +2 -2
- data/lib/arel/nodes/sql_literal.rb +13 -0
- data/lib/arel/nodes/table_alias.rb +4 -0
- data/lib/arel/nodes/update_statement.rb +8 -3
- data/lib/arel/nodes.rb +7 -2
- data/lib/arel/predications.rb +14 -4
- data/lib/arel/select_manager.rb +11 -5
- data/lib/arel/table.rb +9 -6
- data/lib/arel/tree_manager.rb +8 -15
- data/lib/arel/update_manager.rb +20 -5
- data/lib/arel/visitors/dot.rb +81 -90
- data/lib/arel/visitors/mysql.rb +23 -5
- data/lib/arel/visitors/postgresql.rb +1 -22
- data/lib/arel/visitors/to_sql.rb +170 -36
- data/lib/arel/visitors/visitor.rb +2 -2
- data/lib/arel.rb +23 -4
- data/lib/rails/generators/active_record/application_record/USAGE +8 -0
- data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +4 -1
- data/lib/rails/generators/active_record/migration.rb +3 -1
- data/lib/rails/generators/active_record/model/USAGE +113 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -6
- data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
- data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
- data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
- data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
- metadata +100 -14
- data/lib/active_record/connection_adapters/legacy_pool_manager.rb +0 -35
- data/lib/active_record/null_relation.rb +0 -67
@@ -13,17 +13,31 @@ module ActiveRecord
|
|
13
13
|
|
14
14
|
def after_teardown # :nodoc:
|
15
15
|
super
|
16
|
+
ensure
|
16
17
|
teardown_fixtures
|
17
18
|
end
|
18
19
|
|
19
20
|
included do
|
20
|
-
|
21
|
+
##
|
22
|
+
# :singleton-method: fixture_paths
|
23
|
+
#
|
24
|
+
# Returns the ActiveRecord::FixtureSet collection
|
25
|
+
|
26
|
+
##
|
27
|
+
# :singleton-method: fixture_paths=
|
28
|
+
#
|
29
|
+
# :call-seq:
|
30
|
+
# fixture_paths=(fixture_paths)
|
31
|
+
class_attribute :fixture_paths, instance_writer: false, default: []
|
21
32
|
class_attribute :fixture_table_names, default: []
|
22
33
|
class_attribute :fixture_class_names, default: {}
|
23
34
|
class_attribute :use_transactional_tests, default: true
|
24
35
|
class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
|
25
36
|
class_attribute :pre_loaded_fixtures, default: false
|
26
37
|
class_attribute :lock_threads, default: true
|
38
|
+
class_attribute :fixture_sets, default: {}
|
39
|
+
|
40
|
+
ActiveSupport.run_load_hooks(:active_record_fixtures, self)
|
27
41
|
end
|
28
42
|
|
29
43
|
module ClassMethods
|
@@ -41,51 +55,36 @@ module ActiveRecord
|
|
41
55
|
|
42
56
|
def fixtures(*fixture_set_names)
|
43
57
|
if fixture_set_names.first == :all
|
44
|
-
raise StandardError, "No fixture path found. Please set `#{self}.
|
45
|
-
fixture_set_names =
|
46
|
-
|
47
|
-
|
58
|
+
raise StandardError, "No fixture path found. Please set `#{self}.fixture_paths`." if fixture_paths.blank?
|
59
|
+
fixture_set_names = fixture_paths.flat_map do |path|
|
60
|
+
names = Dir[::File.join(path, "{**,*}/*.{yml}")].uniq
|
61
|
+
names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path
|
62
|
+
names.map! { |f| f[path.to_s.size..-5].delete_prefix("/") }
|
63
|
+
end.uniq
|
48
64
|
else
|
49
65
|
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
50
66
|
end
|
51
67
|
|
52
|
-
self.fixture_table_names
|
68
|
+
self.fixture_table_names = (fixture_table_names | fixture_set_names).sort
|
53
69
|
setup_fixture_accessors(fixture_set_names)
|
54
70
|
end
|
55
71
|
|
56
72
|
def setup_fixture_accessors(fixture_set_names = nil)
|
57
73
|
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
58
|
-
|
74
|
+
unless fixture_set_names.empty?
|
75
|
+
self.fixture_sets = fixture_sets.dup
|
59
76
|
fixture_set_names.each do |fs_name|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
65
|
-
return_single_record = fixture_names.size == 1
|
66
|
-
fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
|
67
|
-
|
68
|
-
@fixture_cache[fs_name] ||= {}
|
69
|
-
|
70
|
-
instances = fixture_names.map do |f_name|
|
71
|
-
f_name = f_name.to_s if f_name.is_a?(Symbol)
|
72
|
-
@fixture_cache[fs_name].delete(f_name) if force_reload
|
73
|
-
|
74
|
-
if @loaded_fixtures[fs_name][f_name]
|
75
|
-
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
76
|
-
else
|
77
|
-
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
return_single_record ? instances.first : instances
|
82
|
-
end
|
83
|
-
private accessor_name
|
77
|
+
key = fs_name.to_s.include?("/") ? -fs_name.to_s.tr("/", "_") : fs_name
|
78
|
+
key = -key.to_s if key.is_a?(Symbol)
|
79
|
+
fs_name = -fs_name.to_s if fs_name.is_a?(Symbol)
|
80
|
+
fixture_sets[key] = fs_name
|
84
81
|
end
|
85
82
|
end
|
86
|
-
include methods
|
87
83
|
end
|
88
84
|
|
85
|
+
# Prevents automatically wrapping each specified test in a transaction,
|
86
|
+
# to allow application logic transactions to be tested in a top-level
|
87
|
+
# (non-nested) context.
|
89
88
|
def uses_transaction(*methods)
|
90
89
|
@uses_transaction = [] unless defined?(@uses_transaction)
|
91
90
|
@uses_transaction.concat methods.map(&:to_s)
|
@@ -97,99 +96,109 @@ module ActiveRecord
|
|
97
96
|
end
|
98
97
|
end
|
99
98
|
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
# Generic fixture accessor for fixture names that may conflict with other methods.
|
100
|
+
#
|
101
|
+
# assert_equal "Ruby on Rails", web_sites(:rubyonrails).name
|
102
|
+
# assert_equal "Ruby on Rails", fixture(:web_sites, :rubyonrails).name
|
103
|
+
def fixture(fixture_set_name, *fixture_names)
|
104
|
+
active_record_fixture(fixture_set_name, *fixture_names)
|
103
105
|
end
|
104
106
|
|
105
|
-
|
106
|
-
|
107
|
-
|
107
|
+
private
|
108
|
+
def run_in_transaction?
|
109
|
+
use_transactional_tests &&
|
110
|
+
!self.class.uses_transaction?(name)
|
108
111
|
end
|
109
112
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
113
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
114
|
+
if pre_loaded_fixtures && !use_transactional_tests
|
115
|
+
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
116
|
+
end
|
117
|
+
|
118
|
+
@fixture_cache = {}
|
119
|
+
@fixture_cache_key = [self.class.fixture_table_names.dup, self.class.fixture_paths.dup, self.class.fixture_class_names.dup]
|
120
|
+
@fixture_connection_pools = []
|
121
|
+
@@already_loaded_fixtures ||= {}
|
122
|
+
@connection_subscriber = nil
|
123
|
+
@saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
|
124
|
+
|
125
|
+
if run_in_transaction?
|
126
|
+
# Load fixtures once and begin transaction.
|
127
|
+
@loaded_fixtures = @@already_loaded_fixtures[@fixture_cache_key]
|
128
|
+
unless @loaded_fixtures
|
129
|
+
@@already_loaded_fixtures.clear
|
130
|
+
@loaded_fixtures = @@already_loaded_fixtures[@fixture_cache_key] = load_fixtures(config)
|
131
|
+
end
|
132
|
+
|
133
|
+
setup_transactional_fixtures
|
121
134
|
else
|
135
|
+
# Load fixtures for every test.
|
136
|
+
ActiveRecord::FixtureSet.reset_cache
|
137
|
+
invalidate_already_loaded_fixtures
|
122
138
|
@loaded_fixtures = load_fixtures(config)
|
123
|
-
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
124
139
|
end
|
125
140
|
|
141
|
+
# Instantiate fixtures for every test if requested.
|
142
|
+
instantiate_fixtures if use_instantiated_fixtures
|
143
|
+
end
|
144
|
+
|
145
|
+
def teardown_fixtures
|
146
|
+
# Rollback changes if a transaction is active.
|
147
|
+
if run_in_transaction?
|
148
|
+
teardown_transactional_fixtures
|
149
|
+
else
|
150
|
+
ActiveRecord::FixtureSet.reset_cache
|
151
|
+
invalidate_already_loaded_fixtures
|
152
|
+
end
|
153
|
+
|
154
|
+
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
155
|
+
end
|
156
|
+
|
157
|
+
def invalidate_already_loaded_fixtures
|
158
|
+
@@already_loaded_fixtures.clear
|
159
|
+
end
|
160
|
+
|
161
|
+
def setup_transactional_fixtures
|
162
|
+
setup_shared_connection_pool
|
163
|
+
|
126
164
|
# Begin transactions for connections already established
|
127
|
-
@
|
128
|
-
@
|
129
|
-
|
130
|
-
|
165
|
+
@fixture_connection_pools = ActiveRecord::Base.connection_handler.connection_pool_list(:writing)
|
166
|
+
@fixture_connection_pools.each do |pool|
|
167
|
+
pool.pin_connection!(lock_threads)
|
168
|
+
pool.lease_connection
|
131
169
|
end
|
132
170
|
|
133
171
|
# When connections are established in the future, begin a transaction too
|
134
172
|
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
135
|
-
|
173
|
+
connection_name = payload[:connection_name] if payload.key?(:connection_name)
|
136
174
|
shard = payload[:shard] if payload.key?(:shard)
|
137
|
-
setup_shared_connection_pool if ActiveRecord::Base.legacy_connection_handling
|
138
175
|
|
139
|
-
if
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
connection = nil
|
144
|
-
end
|
145
|
-
|
146
|
-
if connection
|
147
|
-
setup_shared_connection_pool unless ActiveRecord::Base.legacy_connection_handling
|
176
|
+
if connection_name
|
177
|
+
pool = ActiveRecord::Base.connection_handler.retrieve_connection_pool(connection_name, shard: shard)
|
178
|
+
if pool
|
179
|
+
setup_shared_connection_pool
|
148
180
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
@
|
181
|
+
unless @fixture_connection_pools.include?(pool)
|
182
|
+
pool.pin_connection!(lock_threads)
|
183
|
+
pool.lease_connection
|
184
|
+
@fixture_connection_pools << pool
|
153
185
|
end
|
154
186
|
end
|
155
187
|
end
|
156
188
|
end
|
157
|
-
|
158
|
-
# Load fixtures for every test.
|
159
|
-
else
|
160
|
-
ActiveRecord::FixtureSet.reset_cache
|
161
|
-
@@already_loaded_fixtures[self.class] = nil
|
162
|
-
@loaded_fixtures = load_fixtures(config)
|
163
189
|
end
|
164
190
|
|
165
|
-
|
166
|
-
instantiate_fixtures if use_instantiated_fixtures
|
167
|
-
end
|
168
|
-
|
169
|
-
def teardown_fixtures
|
170
|
-
# Rollback changes if a transaction is active.
|
171
|
-
if run_in_transaction?
|
191
|
+
def teardown_transactional_fixtures
|
172
192
|
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
173
|
-
@
|
174
|
-
|
175
|
-
|
193
|
+
unless @fixture_connection_pools.map(&:unpin_connection!).all?
|
194
|
+
# Something caused the transaction to be committed or rolled back
|
195
|
+
# We can no longer trust the database is in a clean state.
|
196
|
+
@@already_loaded_fixtures.clear
|
176
197
|
end
|
177
|
-
@
|
198
|
+
@fixture_connection_pools.clear
|
178
199
|
teardown_shared_connection_pool
|
179
|
-
else
|
180
|
-
ActiveRecord::FixtureSet.reset_cache
|
181
200
|
end
|
182
201
|
|
183
|
-
ActiveRecord::Base.clear_active_connections!
|
184
|
-
end
|
185
|
-
|
186
|
-
def enlist_fixture_connections
|
187
|
-
setup_shared_connection_pool
|
188
|
-
|
189
|
-
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
190
|
-
end
|
191
|
-
|
192
|
-
private
|
193
202
|
# Shares the writing connection pool with connections on
|
194
203
|
# other handlers.
|
195
204
|
#
|
@@ -197,79 +206,43 @@ module ActiveRecord
|
|
197
206
|
# need to share a connection pool so that the reading connection
|
198
207
|
# can see data in the open transaction on the writing connection.
|
199
208
|
def setup_shared_connection_pool
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
pool_config = pool_manager.get_pool_config(nil, shard_name)
|
214
|
-
next if pool_config == writing_pool_config
|
215
|
-
|
216
|
-
@legacy_saved_pool_configs[handler][name][shard_name] = pool_config
|
217
|
-
pool_manager.set_pool_config(nil, shard_name, writing_pool_config)
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
else
|
223
|
-
handler = ActiveRecord::Base.connection_handler
|
224
|
-
|
225
|
-
handler.connection_pool_names.each do |name|
|
226
|
-
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
227
|
-
pool_manager.shard_names.each do |shard_name|
|
228
|
-
writing_pool_config = pool_manager.get_pool_config(ActiveRecord::Base.writing_role, shard_name)
|
229
|
-
@saved_pool_configs[name][shard_name] ||= {}
|
230
|
-
pool_manager.role_names.each do |role|
|
231
|
-
next unless pool_config = pool_manager.get_pool_config(role, shard_name)
|
232
|
-
next if pool_config == writing_pool_config
|
233
|
-
|
234
|
-
@saved_pool_configs[name][shard_name][role] = pool_config
|
235
|
-
pool_manager.set_pool_config(role, shard_name, writing_pool_config)
|
236
|
-
end
|
209
|
+
handler = ActiveRecord::Base.connection_handler
|
210
|
+
|
211
|
+
handler.connection_pool_names.each do |name|
|
212
|
+
pool_manager = handler.send(:connection_name_to_pool_manager)[name]
|
213
|
+
pool_manager.shard_names.each do |shard_name|
|
214
|
+
writing_pool_config = pool_manager.get_pool_config(ActiveRecord.writing_role, shard_name)
|
215
|
+
@saved_pool_configs[name][shard_name] ||= {}
|
216
|
+
pool_manager.role_names.each do |role|
|
217
|
+
next unless pool_config = pool_manager.get_pool_config(role, shard_name)
|
218
|
+
next if pool_config == writing_pool_config
|
219
|
+
|
220
|
+
@saved_pool_configs[name][shard_name][role] = pool_config
|
221
|
+
pool_manager.set_pool_config(role, shard_name, writing_pool_config)
|
237
222
|
end
|
238
223
|
end
|
239
224
|
end
|
240
225
|
end
|
241
226
|
|
242
227
|
def teardown_shared_connection_pool
|
243
|
-
|
244
|
-
@legacy_saved_pool_configs.each_pair do |handler, names|
|
245
|
-
names.each_pair do |name, shards|
|
246
|
-
shards.each_pair do |shard_name, pool_config|
|
247
|
-
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
248
|
-
pool_manager.set_pool_config(nil, shard_name, pool_config)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
252
|
-
else
|
253
|
-
handler = ActiveRecord::Base.connection_handler
|
228
|
+
handler = ActiveRecord::Base.connection_handler
|
254
229
|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
230
|
+
@saved_pool_configs.each_pair do |name, shards|
|
231
|
+
pool_manager = handler.send(:connection_name_to_pool_manager)[name]
|
232
|
+
shards.each_pair do |shard_name, roles|
|
233
|
+
roles.each_pair do |role, pool_config|
|
234
|
+
next unless pool_manager.get_pool_config(role, shard_name)
|
260
235
|
|
261
|
-
|
262
|
-
end
|
236
|
+
pool_manager.set_pool_config(role, shard_name, pool_config)
|
263
237
|
end
|
264
238
|
end
|
265
239
|
end
|
266
240
|
|
267
|
-
@legacy_saved_pool_configs.clear
|
268
241
|
@saved_pool_configs.clear
|
269
242
|
end
|
270
243
|
|
271
244
|
def load_fixtures(config)
|
272
|
-
ActiveRecord::FixtureSet.create_fixtures(
|
245
|
+
ActiveRecord::FixtureSet.create_fixtures(fixture_paths, fixture_table_names, fixture_class_names, config).index_by(&:name)
|
273
246
|
end
|
274
247
|
|
275
248
|
def instantiate_fixtures
|
@@ -287,5 +260,50 @@ module ActiveRecord
|
|
287
260
|
def load_instances?
|
288
261
|
use_instantiated_fixtures != :no_instances
|
289
262
|
end
|
263
|
+
|
264
|
+
def method_missing(method, ...)
|
265
|
+
if fixture_sets.key?(method.name)
|
266
|
+
active_record_fixture(method, ...)
|
267
|
+
else
|
268
|
+
super
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def respond_to_missing?(method, include_private = false)
|
273
|
+
if include_private && fixture_sets.key?(method.name)
|
274
|
+
true
|
275
|
+
else
|
276
|
+
super
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def active_record_fixture(fixture_set_name, *fixture_names)
|
281
|
+
if fs_name = fixture_sets[fixture_set_name.name]
|
282
|
+
access_fixture(fs_name, *fixture_names)
|
283
|
+
else
|
284
|
+
raise StandardError, "No fixture set named '#{fixture_set_name.inspect}'"
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def access_fixture(fs_name, *fixture_names)
|
289
|
+
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
290
|
+
return_single_record = fixture_names.size == 1
|
291
|
+
|
292
|
+
fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
|
293
|
+
@fixture_cache[fs_name] ||= {}
|
294
|
+
|
295
|
+
instances = fixture_names.map do |f_name|
|
296
|
+
f_name = f_name.to_s if f_name.is_a?(Symbol)
|
297
|
+
@fixture_cache[fs_name].delete(f_name) if force_reload
|
298
|
+
|
299
|
+
if @loaded_fixtures[fs_name][f_name]
|
300
|
+
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
301
|
+
else
|
302
|
+
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
return_single_record ? instances.first : instances
|
307
|
+
end
|
290
308
|
end
|
291
309
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Assertions
|
5
|
+
module QueryAssertions
|
6
|
+
# Asserts that the number of SQL queries executed in the given block matches the expected count.
|
7
|
+
#
|
8
|
+
# # Check for exact number of queries
|
9
|
+
# assert_queries_count(1) { Post.first }
|
10
|
+
#
|
11
|
+
# # Check for any number of queries
|
12
|
+
# assert_queries_count { Post.first }
|
13
|
+
#
|
14
|
+
# If the +:include_schema+ option is provided, any queries (including schema related) are counted.
|
15
|
+
#
|
16
|
+
# assert_queries_count(1, include_schema: true) { Post.columns }
|
17
|
+
#
|
18
|
+
def assert_queries_count(count = nil, include_schema: false, &block)
|
19
|
+
ActiveRecord::Base.lease_connection.materialize_transactions
|
20
|
+
|
21
|
+
counter = SQLCounter.new
|
22
|
+
ActiveSupport::Notifications.subscribed(counter, "sql.active_record") do
|
23
|
+
result = _assert_nothing_raised_or_warn("assert_queries_count", &block)
|
24
|
+
queries = include_schema ? counter.log_all : counter.log
|
25
|
+
if count
|
26
|
+
assert_equal count, queries.size, "#{queries.size} instead of #{count} queries were executed. Queries: #{queries.join("\n\n")}"
|
27
|
+
else
|
28
|
+
assert_operator queries.size, :>=, 1, "1 or more queries expected, but none were executed.#{queries.empty? ? '' : "\nQueries:\n#{queries.join("\n")}"}"
|
29
|
+
end
|
30
|
+
result
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Asserts that no SQL queries are executed in the given block.
|
35
|
+
#
|
36
|
+
# assert_no_queries { post.comments }
|
37
|
+
#
|
38
|
+
# If the +:include_schema+ option is provided, any queries (including schema related) are counted.
|
39
|
+
#
|
40
|
+
# assert_no_queries(include_schema: true) { Post.columns }
|
41
|
+
#
|
42
|
+
def assert_no_queries(include_schema: false, &block)
|
43
|
+
assert_queries_count(0, include_schema: include_schema, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Asserts that the SQL queries executed in the given block match expected pattern.
|
47
|
+
#
|
48
|
+
# # Check for exact number of queries
|
49
|
+
# assert_queries_match(/LIMIT \?/, count: 1) { Post.first }
|
50
|
+
#
|
51
|
+
# # Check for any number of queries
|
52
|
+
# assert_queries_match(/LIMIT \?/) { Post.first }
|
53
|
+
#
|
54
|
+
# If the +:include_schema+ option is provided, any queries (including schema related)
|
55
|
+
# that match the matcher are considered.
|
56
|
+
#
|
57
|
+
# assert_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
|
58
|
+
#
|
59
|
+
def assert_queries_match(match, count: nil, include_schema: false, &block)
|
60
|
+
ActiveRecord::Base.lease_connection.materialize_transactions
|
61
|
+
|
62
|
+
counter = SQLCounter.new
|
63
|
+
ActiveSupport::Notifications.subscribed(counter, "sql.active_record") do
|
64
|
+
result = _assert_nothing_raised_or_warn("assert_queries_match", &block)
|
65
|
+
queries = include_schema ? counter.log_all : counter.log
|
66
|
+
matched_queries = queries.select { |query| match === query }
|
67
|
+
|
68
|
+
if count
|
69
|
+
assert_equal count, matched_queries.size, "#{matched_queries.size} instead of #{count} queries were executed.#{queries.empty? ? '' : "\nQueries:\n#{queries.join("\n")}"}"
|
70
|
+
else
|
71
|
+
assert_operator matched_queries.size, :>=, 1, "1 or more queries expected, but none were executed.#{queries.empty? ? '' : "\nQueries:\n#{queries.join("\n")}"}"
|
72
|
+
end
|
73
|
+
|
74
|
+
result
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Asserts that no SQL queries matching the pattern are executed in the given block.
|
79
|
+
#
|
80
|
+
# assert_no_queries_match(/SELECT/i) { post.comments }
|
81
|
+
#
|
82
|
+
# If the +:include_schema+ option is provided, any queries (including schema related)
|
83
|
+
# that match the matcher are counted.
|
84
|
+
#
|
85
|
+
# assert_no_queries_match(/FROM pg_attribute/i, include_schema: true) { Post.columns }
|
86
|
+
#
|
87
|
+
def assert_no_queries_match(match, include_schema: false, &block)
|
88
|
+
assert_queries_match(match, count: 0, include_schema: include_schema, &block)
|
89
|
+
end
|
90
|
+
|
91
|
+
class SQLCounter # :nodoc:
|
92
|
+
attr_reader :log_full, :log_all
|
93
|
+
|
94
|
+
def initialize
|
95
|
+
@log_full = []
|
96
|
+
@log_all = []
|
97
|
+
end
|
98
|
+
|
99
|
+
def log
|
100
|
+
@log_full.map(&:first)
|
101
|
+
end
|
102
|
+
|
103
|
+
def call(*, payload)
|
104
|
+
return if payload[:cached]
|
105
|
+
|
106
|
+
sql = payload[:sql]
|
107
|
+
@log_all << sql
|
108
|
+
|
109
|
+
unless payload[:name] == "SCHEMA"
|
110
|
+
bound_values = (payload[:binds] || []).map do |value|
|
111
|
+
value = value.value_for_database if value.respond_to?(:value_for_database)
|
112
|
+
value
|
113
|
+
end
|
114
|
+
|
115
|
+
@log_full << [sql, bound_values]
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -30,7 +30,7 @@ module ActiveRecord
|
|
30
30
|
#
|
31
31
|
# ActiveRecord::Base.time_zone_aware_types = [:datetime]
|
32
32
|
#
|
33
|
-
# You can also add database
|
33
|
+
# You can also add database-specific timezone aware types. For example, for PostgreSQL:
|
34
34
|
#
|
35
35
|
# ActiveRecord::Base.time_zone_aware_types += [:tsrange, :tstzrange]
|
36
36
|
#
|
@@ -54,8 +54,10 @@ module ActiveRecord
|
|
54
54
|
|
55
55
|
module ClassMethods # :nodoc:
|
56
56
|
def touch_attributes_with_time(*names, time: nil)
|
57
|
+
names = names.map(&:to_s)
|
58
|
+
names = names.map { |name| attribute_aliases[name] || name }
|
57
59
|
attribute_names = timestamp_attributes_for_update_in_model
|
58
|
-
attribute_names |= names
|
60
|
+
attribute_names |= names
|
59
61
|
attribute_names.index_with(time || current_time_from_proper_timezone)
|
60
62
|
end
|
61
63
|
|
@@ -75,9 +77,17 @@ module ActiveRecord
|
|
75
77
|
end
|
76
78
|
|
77
79
|
def current_time_from_proper_timezone
|
78
|
-
default_timezone == :utc ? Time.now.utc : Time.now
|
80
|
+
with_connection { |c| c.default_timezone == :utc ? Time.now.utc : Time.now }
|
79
81
|
end
|
80
82
|
|
83
|
+
protected
|
84
|
+
def reload_schema_from_cache(recursive = true)
|
85
|
+
@timestamp_attributes_for_create_in_model = nil
|
86
|
+
@timestamp_attributes_for_update_in_model = nil
|
87
|
+
@all_timestamp_attributes_in_model = nil
|
88
|
+
super
|
89
|
+
end
|
90
|
+
|
81
91
|
private
|
82
92
|
def timestamp_attributes_for_create
|
83
93
|
["created_at", "created_on"].map! { |name| attribute_aliases[name] || name }
|
@@ -86,16 +96,14 @@ module ActiveRecord
|
|
86
96
|
def timestamp_attributes_for_update
|
87
97
|
["updated_at", "updated_on"].map! { |name| attribute_aliases[name] || name }
|
88
98
|
end
|
89
|
-
|
90
|
-
def reload_schema_from_cache
|
91
|
-
@timestamp_attributes_for_create_in_model = nil
|
92
|
-
@timestamp_attributes_for_update_in_model = nil
|
93
|
-
@all_timestamp_attributes_in_model = nil
|
94
|
-
super
|
95
|
-
end
|
96
99
|
end
|
97
100
|
|
98
101
|
private
|
102
|
+
def init_internals
|
103
|
+
super
|
104
|
+
@_touch_record = nil
|
105
|
+
end
|
106
|
+
|
99
107
|
def _create_record
|
100
108
|
if record_timestamps
|
101
109
|
current_time = current_time_from_proper_timezone
|
@@ -109,6 +117,17 @@ module ActiveRecord
|
|
109
117
|
end
|
110
118
|
|
111
119
|
def _update_record
|
120
|
+
record_update_timestamps
|
121
|
+
|
122
|
+
super
|
123
|
+
end
|
124
|
+
|
125
|
+
def create_or_update(touch: true, **)
|
126
|
+
@_touch_record = touch
|
127
|
+
super
|
128
|
+
end
|
129
|
+
|
130
|
+
def record_update_timestamps
|
112
131
|
if @_touch_record && should_record_timestamps?
|
113
132
|
current_time = current_time_from_proper_timezone
|
114
133
|
|
@@ -118,16 +137,11 @@ module ActiveRecord
|
|
118
137
|
end
|
119
138
|
end
|
120
139
|
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
def create_or_update(touch: true, **)
|
125
|
-
@_touch_record = touch
|
126
|
-
super
|
140
|
+
yield if block_given?
|
127
141
|
end
|
128
142
|
|
129
143
|
def should_record_timestamps?
|
130
|
-
record_timestamps && (!
|
144
|
+
record_timestamps && (!partial_updates? || has_changes_to_save?)
|
131
145
|
end
|
132
146
|
|
133
147
|
def timestamp_attributes_for_create_in_model
|
@@ -148,8 +162,7 @@ module ActiveRecord
|
|
148
162
|
|
149
163
|
def max_updated_column_timestamp
|
150
164
|
timestamp_attributes_for_update_in_model
|
151
|
-
.
|
152
|
-
.compact
|
165
|
+
.filter_map { |attr| (v = self[attr]) && (v.is_a?(::Time) ? v : v.to_time) }
|
153
166
|
.max
|
154
167
|
end
|
155
168
|
|