activerecord 5.2.3 → 6.1.0
Sign up to get free protection for your applications and to get access to all the features.
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
@@ -6,32 +6,30 @@ module ActiveRecord
|
|
6
6
|
module Tasks # :nodoc:
|
7
7
|
class PostgreSQLDatabaseTasks # :nodoc:
|
8
8
|
DEFAULT_ENCODING = ENV["CHARSET"] || "utf8"
|
9
|
-
ON_ERROR_STOP_1 = "ON_ERROR_STOP=1"
|
10
|
-
SQL_COMMENT_BEGIN = "--"
|
9
|
+
ON_ERROR_STOP_1 = "ON_ERROR_STOP=1"
|
10
|
+
SQL_COMMENT_BEGIN = "--"
|
11
11
|
|
12
12
|
delegate :connection, :establish_connection, :clear_active_connections!,
|
13
13
|
to: ActiveRecord::Base
|
14
14
|
|
15
|
-
def
|
16
|
-
|
15
|
+
def self.using_database_configurations?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(db_config)
|
20
|
+
@db_config = db_config
|
21
|
+
@configuration_hash = db_config.configuration_hash
|
17
22
|
end
|
18
23
|
|
19
24
|
def create(master_established = false)
|
20
25
|
establish_master_connection unless master_established
|
21
|
-
connection.create_database
|
22
|
-
|
23
|
-
establish_connection configuration
|
24
|
-
rescue ActiveRecord::StatementInvalid => error
|
25
|
-
if error.cause.is_a?(PG::DuplicateDatabase)
|
26
|
-
raise DatabaseAlreadyExists
|
27
|
-
else
|
28
|
-
raise
|
29
|
-
end
|
26
|
+
connection.create_database(db_config.database, configuration_hash.merge(encoding: encoding))
|
27
|
+
establish_connection(db_config)
|
30
28
|
end
|
31
29
|
|
32
30
|
def drop
|
33
31
|
establish_master_connection
|
34
|
-
connection.drop_database
|
32
|
+
connection.drop_database(db_config.database)
|
35
33
|
end
|
36
34
|
|
37
35
|
def charset
|
@@ -54,14 +52,14 @@ module ActiveRecord
|
|
54
52
|
search_path = \
|
55
53
|
case ActiveRecord::Base.dump_schemas
|
56
54
|
when :schema_search_path
|
57
|
-
|
55
|
+
configuration_hash[:schema_search_path]
|
58
56
|
when :all
|
59
57
|
nil
|
60
58
|
when String
|
61
59
|
ActiveRecord::Base.dump_schemas
|
62
60
|
end
|
63
61
|
|
64
|
-
args = ["-
|
62
|
+
args = ["--schema-only", "--no-privileges", "--no-owner", "--file", filename]
|
65
63
|
args.concat(Array(extra_flags)) if extra_flags
|
66
64
|
unless search_path.blank?
|
67
65
|
args += search_path.split(",").map do |part|
|
@@ -74,7 +72,7 @@ module ActiveRecord
|
|
74
72
|
args += ignore_tables.flat_map { |table| ["-T", table] }
|
75
73
|
end
|
76
74
|
|
77
|
-
args <<
|
75
|
+
args << db_config.database
|
78
76
|
run_cmd("pg_dump", args, "dumping")
|
79
77
|
remove_sql_header_comments(filename)
|
80
78
|
File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" }
|
@@ -82,34 +80,31 @@ module ActiveRecord
|
|
82
80
|
|
83
81
|
def structure_load(filename, extra_flags)
|
84
82
|
set_psql_env
|
85
|
-
args = ["
|
83
|
+
args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--file", filename]
|
86
84
|
args.concat(Array(extra_flags)) if extra_flags
|
87
|
-
args <<
|
85
|
+
args << db_config.database
|
88
86
|
run_cmd("psql", args, "loading")
|
89
87
|
end
|
90
88
|
|
91
89
|
private
|
92
|
-
|
93
|
-
def configuration
|
94
|
-
@configuration
|
95
|
-
end
|
90
|
+
attr_reader :db_config, :configuration_hash
|
96
91
|
|
97
92
|
def encoding
|
98
|
-
|
93
|
+
configuration_hash[:encoding] || DEFAULT_ENCODING
|
99
94
|
end
|
100
95
|
|
101
96
|
def establish_master_connection
|
102
|
-
establish_connection
|
103
|
-
|
104
|
-
|
97
|
+
establish_connection configuration_hash.merge(
|
98
|
+
database: "postgres",
|
99
|
+
schema_search_path: "public"
|
105
100
|
)
|
106
101
|
end
|
107
102
|
|
108
103
|
def set_psql_env
|
109
|
-
ENV["PGHOST"] =
|
110
|
-
ENV["PGPORT"] =
|
111
|
-
ENV["PGPASSWORD"] =
|
112
|
-
ENV["PGUSER"] =
|
104
|
+
ENV["PGHOST"] = db_config.host if db_config.host
|
105
|
+
ENV["PGPORT"] = configuration_hash[:port].to_s if configuration_hash[:port]
|
106
|
+
ENV["PGPASSWORD"] = configuration_hash[:password].to_s if configuration_hash[:password]
|
107
|
+
ENV["PGUSER"] = configuration_hash[:username].to_s if configuration_hash[:username]
|
113
108
|
end
|
114
109
|
|
115
110
|
def run_cmd(cmd, args, action)
|
@@ -117,7 +112,7 @@ module ActiveRecord
|
|
117
112
|
end
|
118
113
|
|
119
114
|
def run_cmd_error(cmd, args, action)
|
120
|
-
msg = "failed to execute:\n"
|
115
|
+
msg = +"failed to execute:\n"
|
121
116
|
msg << "#{cmd} #{args.join(' ')}\n\n"
|
122
117
|
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
123
118
|
msg
|
@@ -5,20 +5,25 @@ module ActiveRecord
|
|
5
5
|
class SQLiteDatabaseTasks # :nodoc:
|
6
6
|
delegate :connection, :establish_connection, to: ActiveRecord::Base
|
7
7
|
|
8
|
-
def
|
9
|
-
|
8
|
+
def self.using_database_configurations?
|
9
|
+
true
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(db_config, root = ActiveRecord::Tasks::DatabaseTasks.root)
|
13
|
+
@db_config = db_config
|
14
|
+
@root = root
|
10
15
|
end
|
11
16
|
|
12
17
|
def create
|
13
|
-
raise DatabaseAlreadyExists if File.exist?(
|
18
|
+
raise DatabaseAlreadyExists if File.exist?(db_config.database)
|
14
19
|
|
15
|
-
establish_connection
|
20
|
+
establish_connection(db_config)
|
16
21
|
connection
|
17
22
|
end
|
18
23
|
|
19
24
|
def drop
|
20
25
|
require "pathname"
|
21
|
-
path = Pathname.new
|
26
|
+
path = Pathname.new(db_config.database)
|
22
27
|
file = path.absolute? ? path.to_s : File.join(root, path)
|
23
28
|
|
24
29
|
FileUtils.rm(file)
|
@@ -40,7 +45,7 @@ module ActiveRecord
|
|
40
45
|
def structure_dump(filename, extra_flags)
|
41
46
|
args = []
|
42
47
|
args.concat(Array(extra_flags)) if extra_flags
|
43
|
-
args <<
|
48
|
+
args << db_config.database
|
44
49
|
|
45
50
|
ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
|
46
51
|
if ignore_tables.any?
|
@@ -53,27 +58,19 @@ module ActiveRecord
|
|
53
58
|
end
|
54
59
|
|
55
60
|
def structure_load(filename, extra_flags)
|
56
|
-
dbfile = configuration["database"]
|
57
61
|
flags = extra_flags.join(" ") if extra_flags
|
58
|
-
`sqlite3 #{flags} #{
|
62
|
+
`sqlite3 #{flags} #{db_config.database} < "#{filename}"`
|
59
63
|
end
|
60
64
|
|
61
65
|
private
|
62
|
-
|
63
|
-
def configuration
|
64
|
-
@configuration
|
65
|
-
end
|
66
|
-
|
67
|
-
def root
|
68
|
-
@root
|
69
|
-
end
|
66
|
+
attr_reader :db_config, :root
|
70
67
|
|
71
68
|
def run_cmd(cmd, args, out)
|
72
69
|
fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
|
73
70
|
end
|
74
71
|
|
75
72
|
def run_cmd_error(cmd, args)
|
76
|
-
msg = "failed to execute:\n"
|
73
|
+
msg = +"failed to execute:\n"
|
77
74
|
msg << "#{cmd} #{args.join(' ')}\n\n"
|
78
75
|
msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n"
|
79
76
|
msg
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/testing/parallelization"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module TestDatabases # :nodoc:
|
7
|
+
ActiveSupport::Testing::Parallelization.after_fork_hook do |i|
|
8
|
+
create_and_load_schema(i, env_name: ActiveRecord::ConnectionHandling::DEFAULT_ENV.call)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.create_and_load_schema(i, env_name:)
|
12
|
+
old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"
|
13
|
+
|
14
|
+
ActiveRecord::Base.configurations.configs_for(env_name: env_name).each do |db_config|
|
15
|
+
db_config._database = "#{db_config.database}-#{i}"
|
16
|
+
|
17
|
+
ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config, ActiveRecord::Base.schema_format, nil)
|
18
|
+
end
|
19
|
+
ensure
|
20
|
+
ActiveRecord::Base.establish_connection
|
21
|
+
ENV["VERBOSE"] = old
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,246 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/enumerable"
|
4
|
+
|
5
|
+
module ActiveRecord
|
6
|
+
module TestFixtures
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
def before_setup # :nodoc:
|
10
|
+
setup_fixtures
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def after_teardown # :nodoc:
|
15
|
+
super
|
16
|
+
teardown_fixtures
|
17
|
+
end
|
18
|
+
|
19
|
+
included do
|
20
|
+
class_attribute :fixture_path, instance_writer: false
|
21
|
+
class_attribute :fixture_table_names, default: []
|
22
|
+
class_attribute :fixture_class_names, default: {}
|
23
|
+
class_attribute :use_transactional_tests, default: true
|
24
|
+
class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
|
25
|
+
class_attribute :pre_loaded_fixtures, default: false
|
26
|
+
class_attribute :lock_threads, default: true
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
# Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
|
31
|
+
#
|
32
|
+
# Examples:
|
33
|
+
#
|
34
|
+
# set_fixture_class some_fixture: SomeModel,
|
35
|
+
# 'namespaced/fixture' => Another::Model
|
36
|
+
#
|
37
|
+
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
38
|
+
def set_fixture_class(class_names = {})
|
39
|
+
self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
|
40
|
+
end
|
41
|
+
|
42
|
+
def fixtures(*fixture_set_names)
|
43
|
+
if fixture_set_names.first == :all
|
44
|
+
raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
|
45
|
+
fixture_set_names = Dir[::File.join(fixture_path, "{**,*}/*.{yml}")].uniq
|
46
|
+
fixture_set_names.reject! { |f| f.start_with?(file_fixture_path.to_s) } if defined?(file_fixture_path) && file_fixture_path
|
47
|
+
fixture_set_names.map! { |f| f[fixture_path.to_s.size..-5].delete_prefix("/") }
|
48
|
+
else
|
49
|
+
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
50
|
+
end
|
51
|
+
|
52
|
+
self.fixture_table_names |= fixture_set_names
|
53
|
+
setup_fixture_accessors(fixture_set_names)
|
54
|
+
end
|
55
|
+
|
56
|
+
def setup_fixture_accessors(fixture_set_names = nil)
|
57
|
+
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
58
|
+
methods = Module.new do
|
59
|
+
fixture_set_names.each do |fs_name|
|
60
|
+
fs_name = fs_name.to_s
|
61
|
+
accessor_name = fs_name.tr("/", "_").to_sym
|
62
|
+
|
63
|
+
define_method(accessor_name) do |*fixture_names|
|
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
|
84
|
+
end
|
85
|
+
end
|
86
|
+
include methods
|
87
|
+
end
|
88
|
+
|
89
|
+
def uses_transaction(*methods)
|
90
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
91
|
+
@uses_transaction.concat methods.map(&:to_s)
|
92
|
+
end
|
93
|
+
|
94
|
+
def uses_transaction?(method)
|
95
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
96
|
+
@uses_transaction.include?(method.to_s)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def run_in_transaction?
|
101
|
+
use_transactional_tests &&
|
102
|
+
!self.class.uses_transaction?(name)
|
103
|
+
end
|
104
|
+
|
105
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
106
|
+
if pre_loaded_fixtures && !use_transactional_tests
|
107
|
+
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
108
|
+
end
|
109
|
+
|
110
|
+
@fixture_cache = {}
|
111
|
+
@fixture_connections = []
|
112
|
+
@@already_loaded_fixtures ||= {}
|
113
|
+
@connection_subscriber = nil
|
114
|
+
|
115
|
+
# Load fixtures once and begin transaction.
|
116
|
+
if run_in_transaction?
|
117
|
+
if @@already_loaded_fixtures[self.class]
|
118
|
+
@loaded_fixtures = @@already_loaded_fixtures[self.class]
|
119
|
+
else
|
120
|
+
@loaded_fixtures = load_fixtures(config)
|
121
|
+
@@already_loaded_fixtures[self.class] = @loaded_fixtures
|
122
|
+
end
|
123
|
+
|
124
|
+
# Begin transactions for connections already established
|
125
|
+
@fixture_connections = enlist_fixture_connections
|
126
|
+
@fixture_connections.each do |connection|
|
127
|
+
connection.begin_transaction joinable: false, _lazy: false
|
128
|
+
connection.pool.lock_thread = true if lock_threads
|
129
|
+
end
|
130
|
+
|
131
|
+
# When connections are established in the future, begin a transaction too
|
132
|
+
@connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
|
133
|
+
spec_name = payload[:spec_name] if payload.key?(:spec_name)
|
134
|
+
shard = payload[:shard] if payload.key?(:shard)
|
135
|
+
setup_shared_connection_pool
|
136
|
+
|
137
|
+
if spec_name
|
138
|
+
begin
|
139
|
+
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name, shard: shard)
|
140
|
+
rescue ConnectionNotEstablished
|
141
|
+
connection = nil
|
142
|
+
end
|
143
|
+
|
144
|
+
if connection && !@fixture_connections.include?(connection)
|
145
|
+
connection.begin_transaction joinable: false, _lazy: false
|
146
|
+
connection.pool.lock_thread = true if lock_threads
|
147
|
+
@fixture_connections << connection
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Load fixtures for every test.
|
153
|
+
else
|
154
|
+
ActiveRecord::FixtureSet.reset_cache
|
155
|
+
@@already_loaded_fixtures[self.class] = nil
|
156
|
+
@loaded_fixtures = load_fixtures(config)
|
157
|
+
end
|
158
|
+
|
159
|
+
# Instantiate fixtures for every test if requested.
|
160
|
+
instantiate_fixtures if use_instantiated_fixtures
|
161
|
+
end
|
162
|
+
|
163
|
+
def teardown_fixtures
|
164
|
+
# Rollback changes if a transaction is active.
|
165
|
+
if run_in_transaction?
|
166
|
+
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
167
|
+
@fixture_connections.each do |connection|
|
168
|
+
connection.rollback_transaction if connection.transaction_open?
|
169
|
+
connection.pool.lock_thread = false
|
170
|
+
end
|
171
|
+
@fixture_connections.clear
|
172
|
+
else
|
173
|
+
ActiveRecord::FixtureSet.reset_cache
|
174
|
+
end
|
175
|
+
|
176
|
+
ActiveRecord::Base.clear_active_connections!
|
177
|
+
end
|
178
|
+
|
179
|
+
def enlist_fixture_connections
|
180
|
+
setup_shared_connection_pool
|
181
|
+
|
182
|
+
ActiveRecord::Base.connection_handler.connection_pool_list.map(&:connection)
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
# Shares the writing connection pool with connections on
|
187
|
+
# other handlers.
|
188
|
+
#
|
189
|
+
# In an application with a primary and replica the test fixtures
|
190
|
+
# need to share a connection pool so that the reading connection
|
191
|
+
# can see data in the open transaction on the writing connection.
|
192
|
+
def setup_shared_connection_pool
|
193
|
+
if ActiveRecord::Base.legacy_connection_handling
|
194
|
+
writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
|
195
|
+
|
196
|
+
ActiveRecord::Base.connection_handlers.values.each do |handler|
|
197
|
+
if handler != writing_handler
|
198
|
+
handler.connection_pool_names.each do |name|
|
199
|
+
writing_pool_manager = writing_handler.send(:owner_to_pool_manager)[name]
|
200
|
+
return unless writing_pool_manager
|
201
|
+
|
202
|
+
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
203
|
+
pool_manager.shard_names.each do |shard_name|
|
204
|
+
writing_pool_config = writing_pool_manager.get_pool_config(nil, shard_name)
|
205
|
+
pool_manager.set_pool_config(nil, shard_name, writing_pool_config)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
else
|
211
|
+
handler = ActiveRecord::Base.connection_handler
|
212
|
+
|
213
|
+
handler.connection_pool_names.each do |name|
|
214
|
+
pool_manager = handler.send(:owner_to_pool_manager)[name]
|
215
|
+
pool_manager.shard_names.each do |shard_name|
|
216
|
+
writing_pool_config = pool_manager.get_pool_config(ActiveRecord::Base.writing_role, shard_name)
|
217
|
+
pool_manager.role_names.each do |role|
|
218
|
+
next unless pool_manager.get_pool_config(role, shard_name)
|
219
|
+
pool_manager.set_pool_config(role, shard_name, writing_pool_config)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def load_fixtures(config)
|
227
|
+
ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config).index_by(&:name)
|
228
|
+
end
|
229
|
+
|
230
|
+
def instantiate_fixtures
|
231
|
+
if pre_loaded_fixtures
|
232
|
+
raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
233
|
+
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
234
|
+
else
|
235
|
+
raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
|
236
|
+
@loaded_fixtures.each_value do |fixture_set|
|
237
|
+
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def load_instances?
|
243
|
+
use_instantiated_fixtures != :no_instances
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -56,54 +56,60 @@ module ActiveRecord
|
|
56
56
|
def touch_attributes_with_time(*names, time: nil)
|
57
57
|
attribute_names = timestamp_attributes_for_update_in_model
|
58
58
|
attribute_names |= names.map(&:to_s)
|
59
|
-
time
|
60
|
-
attribute_names.each_with_object({}) { |attr_name, result| result[attr_name] = time }
|
59
|
+
attribute_names.index_with(time || current_time_from_proper_timezone)
|
61
60
|
end
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
timestamp_attributes_for_create
|
66
|
-
|
62
|
+
def timestamp_attributes_for_create_in_model
|
63
|
+
@timestamp_attributes_for_create_in_model ||=
|
64
|
+
(timestamp_attributes_for_create & column_names).freeze
|
65
|
+
end
|
67
66
|
|
68
|
-
|
69
|
-
|
70
|
-
|
67
|
+
def timestamp_attributes_for_update_in_model
|
68
|
+
@timestamp_attributes_for_update_in_model ||=
|
69
|
+
(timestamp_attributes_for_update & column_names).freeze
|
70
|
+
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
def all_timestamp_attributes_in_model
|
73
|
+
@all_timestamp_attributes_in_model ||=
|
74
|
+
(timestamp_attributes_for_create_in_model + timestamp_attributes_for_update_in_model).freeze
|
75
|
+
end
|
76
|
+
|
77
|
+
def current_time_from_proper_timezone
|
78
|
+
default_timezone == :utc ? Time.now.utc : Time.now
|
79
|
+
end
|
75
80
|
|
81
|
+
private
|
76
82
|
def timestamp_attributes_for_create
|
77
|
-
["created_at", "created_on"]
|
83
|
+
["created_at", "created_on"].map! { |name| attribute_aliases[name] || name }
|
78
84
|
end
|
79
85
|
|
80
86
|
def timestamp_attributes_for_update
|
81
|
-
["updated_at", "updated_on"]
|
87
|
+
["updated_at", "updated_on"].map! { |name| attribute_aliases[name] || name }
|
82
88
|
end
|
83
89
|
|
84
|
-
def
|
85
|
-
|
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
|
86
95
|
end
|
87
96
|
end
|
88
97
|
|
89
98
|
private
|
90
|
-
|
91
99
|
def _create_record
|
92
100
|
if record_timestamps
|
93
101
|
current_time = current_time_from_proper_timezone
|
94
102
|
|
95
103
|
all_timestamp_attributes_in_model.each do |column|
|
96
|
-
|
97
|
-
_write_attribute(column, current_time)
|
98
|
-
end
|
104
|
+
_write_attribute(column, current_time) unless _read_attribute(column)
|
99
105
|
end
|
100
106
|
end
|
101
107
|
|
102
108
|
super
|
103
109
|
end
|
104
110
|
|
105
|
-
def _update_record
|
106
|
-
if
|
111
|
+
def _update_record
|
112
|
+
if @_touch_record && should_record_timestamps?
|
107
113
|
current_time = current_time_from_proper_timezone
|
108
114
|
|
109
115
|
timestamp_attributes_for_update_in_model.each do |column|
|
@@ -111,7 +117,13 @@ module ActiveRecord
|
|
111
117
|
_write_attribute(column, current_time)
|
112
118
|
end
|
113
119
|
end
|
114
|
-
|
120
|
+
|
121
|
+
super
|
122
|
+
end
|
123
|
+
|
124
|
+
def create_or_update(touch: true, **)
|
125
|
+
@_touch_record = touch
|
126
|
+
super
|
115
127
|
end
|
116
128
|
|
117
129
|
def should_record_timestamps?
|
@@ -119,26 +131,25 @@ module ActiveRecord
|
|
119
131
|
end
|
120
132
|
|
121
133
|
def timestamp_attributes_for_create_in_model
|
122
|
-
self.class.
|
134
|
+
self.class.timestamp_attributes_for_create_in_model
|
123
135
|
end
|
124
136
|
|
125
137
|
def timestamp_attributes_for_update_in_model
|
126
|
-
self.class.
|
138
|
+
self.class.timestamp_attributes_for_update_in_model
|
127
139
|
end
|
128
140
|
|
129
141
|
def all_timestamp_attributes_in_model
|
130
|
-
self.class.
|
142
|
+
self.class.all_timestamp_attributes_in_model
|
131
143
|
end
|
132
144
|
|
133
145
|
def current_time_from_proper_timezone
|
134
|
-
self.class.
|
146
|
+
self.class.current_time_from_proper_timezone
|
135
147
|
end
|
136
148
|
|
137
|
-
def max_updated_column_timestamp
|
138
|
-
|
139
|
-
.map { |attr| self[attr] }
|
149
|
+
def max_updated_column_timestamp
|
150
|
+
timestamp_attributes_for_update_in_model
|
151
|
+
.map { |attr| self[attr]&.to_time }
|
140
152
|
.compact
|
141
|
-
.map(&:to_time)
|
142
153
|
.max
|
143
154
|
end
|
144
155
|
|
@@ -146,7 +157,7 @@ module ActiveRecord
|
|
146
157
|
def clear_timestamp_attributes
|
147
158
|
all_timestamp_attributes_in_model.each do |attribute_name|
|
148
159
|
self[attribute_name] = nil
|
149
|
-
|
160
|
+
clear_attribute_change(attribute_name)
|
150
161
|
end
|
151
162
|
end
|
152
163
|
end
|
@@ -2,27 +2,26 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
# = Active Record Touch Later
|
5
|
-
module TouchLater
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
before_commit_without_transaction_enrollment :touch_deferred_attributes
|
5
|
+
module TouchLater # :nodoc:
|
6
|
+
def before_committed!
|
7
|
+
touch_deferred_attributes if has_defer_touch_attrs? && persisted?
|
8
|
+
super
|
10
9
|
end
|
11
10
|
|
12
11
|
def touch_later(*names) # :nodoc:
|
13
|
-
unless persisted?
|
14
|
-
raise ActiveRecordError, <<-MSG.squish
|
15
|
-
cannot touch on a new or destroyed record object. Consider using
|
16
|
-
persisted?, new_record?, or destroyed? before touching
|
17
|
-
MSG
|
18
|
-
end
|
12
|
+
_raise_record_not_touched_error unless persisted?
|
19
13
|
|
20
14
|
@_defer_touch_attrs ||= timestamp_attributes_for_update_in_model
|
21
|
-
@_defer_touch_attrs |= names
|
15
|
+
@_defer_touch_attrs |= names.map! do |name|
|
16
|
+
name = name.to_s
|
17
|
+
self.class.attribute_aliases[name] || name
|
18
|
+
end unless names.empty?
|
19
|
+
|
22
20
|
@_touch_time = current_time_from_proper_timezone
|
23
21
|
|
24
22
|
surreptitiously_touch @_defer_touch_attrs
|
25
|
-
|
23
|
+
add_to_transaction
|
24
|
+
@_new_record_before_last_commit ||= false
|
26
25
|
|
27
26
|
# touch the parents as we are not calling the after_save callbacks
|
28
27
|
self.class.reflect_on_all_associations(:belongs_to).each do |r|
|
@@ -35,22 +34,24 @@ module ActiveRecord
|
|
35
34
|
def touch(*names, time: nil) # :nodoc:
|
36
35
|
if has_defer_touch_attrs?
|
37
36
|
names |= @_defer_touch_attrs
|
37
|
+
super(*names, time: time)
|
38
|
+
@_defer_touch_attrs, @_touch_time = nil, nil
|
39
|
+
else
|
40
|
+
super
|
38
41
|
end
|
39
|
-
super(*names, time: time)
|
40
42
|
end
|
41
43
|
|
42
44
|
private
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
45
|
+
def surreptitiously_touch(attr_names)
|
46
|
+
attr_names.each do |attr_name|
|
47
|
+
_write_attribute(attr_name, @_touch_time)
|
48
|
+
clear_attribute_change(attr_name)
|
49
|
+
end
|
47
50
|
end
|
48
51
|
|
49
52
|
def touch_deferred_attributes
|
50
|
-
|
51
|
-
|
52
|
-
@_defer_touch_attrs, @_touch_time = nil, nil
|
53
|
-
end
|
53
|
+
@_skip_dirty_tracking = true
|
54
|
+
touch(time: @_touch_time)
|
54
55
|
end
|
55
56
|
|
56
57
|
def has_defer_touch_attrs?
|