activerecord 5.2.8.1 → 6.0.6.1
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 +938 -573
- data/MIT-LICENSE +3 -1
- data/README.rdoc +5 -3
- data/examples/performance.rb +1 -1
- data/lib/active_record/advisory_lock_base.rb +18 -0
- data/lib/active_record/aggregations.rb +4 -3
- data/lib/active_record/association_relation.rb +10 -8
- data/lib/active_record/associations/alias_tracker.rb +0 -1
- data/lib/active_record/associations/association.rb +55 -19
- data/lib/active_record/associations/association_scope.rb +11 -7
- data/lib/active_record/associations/belongs_to_association.rb +36 -42
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
- data/lib/active_record/associations/builder/association.rb +14 -18
- data/lib/active_record/associations/builder/belongs_to.rb +19 -52
- data/lib/active_record/associations/builder/collection_association.rb +3 -13
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -40
- data/lib/active_record/associations/builder/has_many.rb +2 -0
- data/lib/active_record/associations/builder/has_one.rb +35 -1
- data/lib/active_record/associations/builder/singular_association.rb +2 -0
- data/lib/active_record/associations/collection_association.rb +19 -23
- data/lib/active_record/associations/collection_proxy.rb +14 -17
- data/lib/active_record/associations/foreign_association.rb +7 -0
- data/lib/active_record/associations/has_many_association.rb +2 -11
- data/lib/active_record/associations/has_many_through_association.rb +14 -14
- data/lib/active_record/associations/has_one_association.rb +28 -30
- data/lib/active_record/associations/has_one_through_association.rb +5 -5
- data/lib/active_record/associations/join_dependency/join_association.rb +16 -10
- data/lib/active_record/associations/join_dependency/join_part.rb +4 -4
- data/lib/active_record/associations/join_dependency.rb +47 -30
- data/lib/active_record/associations/preloader/association.rb +61 -41
- data/lib/active_record/associations/preloader/through_association.rb +48 -39
- data/lib/active_record/associations/preloader.rb +44 -33
- data/lib/active_record/associations/singular_association.rb +2 -16
- data/lib/active_record/associations/through_association.rb +1 -1
- data/lib/active_record/associations.rb +21 -16
- data/lib/active_record/attribute_assignment.rb +7 -11
- data/lib/active_record/attribute_decorators.rb +0 -2
- data/lib/active_record/attribute_methods/before_type_cast.rb +4 -2
- data/lib/active_record/attribute_methods/dirty.rb +111 -40
- data/lib/active_record/attribute_methods/primary_key.rb +15 -24
- data/lib/active_record/attribute_methods/query.rb +2 -3
- data/lib/active_record/attribute_methods/read.rb +15 -54
- data/lib/active_record/attribute_methods/serialization.rb +1 -2
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -3
- data/lib/active_record/attribute_methods/write.rb +17 -25
- data/lib/active_record/attribute_methods.rb +28 -100
- data/lib/active_record/attributes.rb +13 -1
- data/lib/active_record/autosave_association.rb +12 -14
- data/lib/active_record/base.rb +2 -3
- data/lib/active_record/callbacks.rb +6 -21
- data/lib/active_record/coders/yaml_column.rb +15 -6
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +109 -18
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +102 -124
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +18 -9
- data/lib/active_record/connection_adapters/abstract/quoting.rb +77 -17
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +20 -14
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +105 -72
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +175 -79
- data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -57
- data/lib/active_record/connection_adapters/abstract_adapter.rb +197 -43
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +149 -217
- data/lib/active_record/connection_adapters/column.rb +17 -13
- data/lib/active_record/connection_adapters/connection_specification.rb +54 -45
- data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
- data/lib/active_record/connection_adapters/mysql/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/database_statements.rb +70 -14
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +0 -1
- data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/mysql/schema_creation.rb +4 -6
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -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 +6 -10
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +26 -10
- data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +26 -1
- 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/date_time.rb +8 -0
- 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/legacy_point.rb +1 -2
- data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -2
- 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 +5 -3
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +14 -3
- 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 +63 -75
- data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
- data/lib/active_record/connection_adapters/postgresql/utils.rb +0 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +168 -75
- data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
- data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
- data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +119 -0
- data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -7
- data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +43 -12
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +137 -147
- data/lib/active_record/connection_adapters/statement_pool.rb +0 -1
- data/lib/active_record/connection_handling.rb +139 -26
- data/lib/active_record/core.rb +108 -67
- data/lib/active_record/counter_cache.rb +8 -30
- data/lib/active_record/database_configurations/database_config.rb +37 -0
- data/lib/active_record/database_configurations/hash_config.rb +50 -0
- data/lib/active_record/database_configurations/url_config.rb +78 -0
- data/lib/active_record/database_configurations.rb +233 -0
- data/lib/active_record/dynamic_matchers.rb +3 -4
- data/lib/active_record/enum.rb +44 -7
- data/lib/active_record/errors.rb +15 -7
- data/lib/active_record/explain.rb +1 -2
- data/lib/active_record/fixture_set/model_metadata.rb +33 -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 +144 -474
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +13 -6
- data/lib/active_record/insert_all.rb +179 -0
- data/lib/active_record/integration.rb +68 -16
- data/lib/active_record/internal_metadata.rb +11 -3
- data/lib/active_record/locking/optimistic.rb +14 -7
- data/lib/active_record/locking/pessimistic.rb +3 -3
- data/lib/active_record/log_subscriber.rb +8 -27
- data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
- data/lib/active_record/middleware/database_selector/resolver.rb +87 -0
- data/lib/active_record/middleware/database_selector.rb +74 -0
- data/lib/active_record/migration/command_recorder.rb +54 -22
- data/lib/active_record/migration/compatibility.rb +79 -52
- data/lib/active_record/migration/join_table.rb +0 -1
- data/lib/active_record/migration.rb +104 -85
- data/lib/active_record/model_schema.rb +62 -11
- data/lib/active_record/nested_attributes.rb +2 -4
- data/lib/active_record/no_touching.rb +9 -2
- data/lib/active_record/null_relation.rb +0 -1
- data/lib/active_record/persistence.rb +232 -29
- data/lib/active_record/query_cache.rb +11 -4
- data/lib/active_record/querying.rb +33 -21
- data/lib/active_record/railtie.rb +80 -61
- data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
- data/lib/active_record/railties/controller_runtime.rb +30 -35
- data/lib/active_record/railties/databases.rake +199 -46
- data/lib/active_record/reflection.rb +51 -51
- data/lib/active_record/relation/batches.rb +13 -11
- data/lib/active_record/relation/calculations.rb +55 -49
- data/lib/active_record/relation/delegation.rb +35 -50
- data/lib/active_record/relation/finder_methods.rb +23 -28
- data/lib/active_record/relation/from_clause.rb +4 -0
- data/lib/active_record/relation/merger.rb +12 -17
- data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
- data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
- data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
- data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
- data/lib/active_record/relation/predicate_builder.rb +5 -11
- data/lib/active_record/relation/query_attribute.rb +13 -8
- data/lib/active_record/relation/query_methods.rb +234 -69
- data/lib/active_record/relation/spawn_methods.rb +1 -2
- data/lib/active_record/relation/where_clause.rb +14 -11
- data/lib/active_record/relation/where_clause_factory.rb +1 -2
- data/lib/active_record/relation.rb +326 -81
- data/lib/active_record/result.rb +30 -12
- data/lib/active_record/sanitization.rb +32 -40
- data/lib/active_record/schema.rb +2 -11
- data/lib/active_record/schema_dumper.rb +22 -7
- data/lib/active_record/schema_migration.rb +6 -2
- data/lib/active_record/scoping/default.rb +4 -6
- data/lib/active_record/scoping/named.rb +25 -16
- data/lib/active_record/scoping.rb +8 -9
- data/lib/active_record/statement_cache.rb +30 -3
- data/lib/active_record/store.rb +87 -8
- data/lib/active_record/suppressor.rb +2 -2
- data/lib/active_record/table_metadata.rb +23 -15
- data/lib/active_record/tasks/database_tasks.rb +194 -25
- data/lib/active_record/tasks/mysql_database_tasks.rb +5 -6
- data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -8
- data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -9
- data/lib/active_record/test_databases.rb +23 -0
- data/lib/active_record/test_fixtures.rb +243 -0
- data/lib/active_record/timestamp.rb +39 -26
- data/lib/active_record/touch_later.rb +5 -4
- data/lib/active_record/transactions.rb +64 -73
- 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 +0 -1
- 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 +3 -5
- data/lib/active_record/type_caster/connection.rb +15 -14
- data/lib/active_record/type_caster/map.rb +1 -4
- data/lib/active_record/validations/associated.rb +0 -1
- data/lib/active_record/validations/uniqueness.rb +15 -27
- data/lib/active_record/validations.rb +3 -3
- data/lib/active_record.rb +10 -2
- data/lib/arel/alias_predication.rb +9 -0
- data/lib/arel/attributes/attribute.rb +37 -0
- data/lib/arel/attributes.rb +22 -0
- data/lib/arel/collectors/bind.rb +24 -0
- data/lib/arel/collectors/composite.rb +31 -0
- data/lib/arel/collectors/plain_string.rb +20 -0
- data/lib/arel/collectors/sql_string.rb +20 -0
- data/lib/arel/collectors/substitute_binds.rb +28 -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 +52 -0
- data/lib/arel/nodes/bind_param.rb +36 -0
- data/lib/arel/nodes/case.rb +55 -0
- data/lib/arel/nodes/casted.rb +50 -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 +18 -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 +8 -0
- data/lib/arel/nodes/in.rb +8 -0
- data/lib/arel/nodes/infix_operation.rb +80 -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 +50 -0
- data/lib/arel/nodes/node_expression.rb +13 -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 +16 -0
- data/lib/arel/nodes/string_join.rb +11 -0
- data/lib/arel/nodes/table_alias.rb +27 -0
- data/lib/arel/nodes/terminal.rb +16 -0
- data/lib/arel/nodes/true.rb +16 -0
- data/lib/arel/nodes/unary.rb +45 -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 +68 -0
- data/lib/arel/order_predications.rb +13 -0
- data/lib/arel/predications.rb +256 -0
- data/lib/arel/select_manager.rb +271 -0
- data/lib/arel/table.rb +110 -0
- data/lib/arel/tree_manager.rb +72 -0
- data/lib/arel/update_manager.rb +34 -0
- data/lib/arel/visitors/depth_first.rb +203 -0
- data/lib/arel/visitors/dot.rb +296 -0
- data/lib/arel/visitors/ibm_db.rb +34 -0
- data/lib/arel/visitors/informix.rb +62 -0
- data/lib/arel/visitors/mssql.rb +156 -0
- data/lib/arel/visitors/mysql.rb +83 -0
- data/lib/arel/visitors/oracle.rb +158 -0
- data/lib/arel/visitors/oracle12.rb +65 -0
- data/lib/arel/visitors/postgresql.rb +109 -0
- data/lib/arel/visitors/sqlite.rb +38 -0
- data/lib/arel/visitors/to_sql.rb +888 -0
- data/lib/arel/visitors/visitor.rb +45 -0
- data/lib/arel/visitors/where_sql.rb +22 -0
- data/lib/arel/visitors.rb +20 -0
- data/lib/arel/window_predications.rb +9 -0
- data/lib/arel.rb +62 -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 +2 -5
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
- data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
- data/lib/rails/generators/active_record/migration.rb +14 -2
- data/lib/rails/generators/active_record/model/model_generator.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
- metadata +113 -26
- data/lib/active_record/collection_cache_key.rb +0 -53
@@ -59,21 +59,14 @@ module ActiveRecord
|
|
59
59
|
end
|
60
60
|
|
61
61
|
private
|
62
|
-
|
63
|
-
def configuration
|
64
|
-
@configuration
|
65
|
-
end
|
66
|
-
|
67
|
-
def root
|
68
|
-
@root
|
69
|
-
end
|
62
|
+
attr_reader :configuration, :root
|
70
63
|
|
71
64
|
def run_cmd(cmd, args, out)
|
72
65
|
fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
|
73
66
|
end
|
74
67
|
|
75
68
|
def run_cmd_error(cmd, args)
|
76
|
-
msg = "failed to execute:\n"
|
69
|
+
msg = +"failed to execute:\n"
|
77
70
|
msg << "#{cmd} #{args.join(' ')}\n\n"
|
78
71
|
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
72
|
msg
|
@@ -0,0 +1,23 @@
|
|
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: Rails.env)
|
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.config["database"] += "-#{i}"
|
16
|
+
ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config.config, ActiveRecord::Base.schema_format, nil, env_name, db_config.spec_name)
|
17
|
+
end
|
18
|
+
ensure
|
19
|
+
ActiveRecord::Base.establish_connection(Rails.env.to_sym)
|
20
|
+
ENV["VERBOSE"] = old
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,243 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module TestFixtures
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def before_setup # :nodoc:
|
8
|
+
setup_fixtures
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def after_teardown # :nodoc:
|
13
|
+
super
|
14
|
+
teardown_fixtures
|
15
|
+
end
|
16
|
+
|
17
|
+
included do
|
18
|
+
class_attribute :fixture_path, instance_writer: false
|
19
|
+
class_attribute :fixture_table_names, default: []
|
20
|
+
class_attribute :fixture_class_names, default: {}
|
21
|
+
class_attribute :use_transactional_tests, default: true
|
22
|
+
class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
|
23
|
+
class_attribute :pre_loaded_fixtures, default: false
|
24
|
+
class_attribute :config, default: ActiveRecord::Base
|
25
|
+
class_attribute :lock_threads, default: true
|
26
|
+
end
|
27
|
+
|
28
|
+
module ClassMethods
|
29
|
+
# Sets the model class for a fixture when the class name cannot be inferred from the fixture name.
|
30
|
+
#
|
31
|
+
# Examples:
|
32
|
+
#
|
33
|
+
# set_fixture_class some_fixture: SomeModel,
|
34
|
+
# 'namespaced/fixture' => Another::Model
|
35
|
+
#
|
36
|
+
# The keys must be the fixture names, that coincide with the short paths to the fixture files.
|
37
|
+
def set_fixture_class(class_names = {})
|
38
|
+
self.fixture_class_names = fixture_class_names.merge(class_names.stringify_keys)
|
39
|
+
end
|
40
|
+
|
41
|
+
def fixtures(*fixture_set_names)
|
42
|
+
if fixture_set_names.first == :all
|
43
|
+
raise StandardError, "No fixture path found. Please set `#{self}.fixture_path`." if fixture_path.blank?
|
44
|
+
fixture_set_names = Dir["#{fixture_path}/{**,*}/*.{yml}"].uniq
|
45
|
+
fixture_set_names.map! { |f| f[(fixture_path.to_s.size + 1)..-5] }
|
46
|
+
else
|
47
|
+
fixture_set_names = fixture_set_names.flatten.map(&:to_s)
|
48
|
+
end
|
49
|
+
|
50
|
+
self.fixture_table_names |= fixture_set_names
|
51
|
+
setup_fixture_accessors(fixture_set_names)
|
52
|
+
end
|
53
|
+
|
54
|
+
def setup_fixture_accessors(fixture_set_names = nil)
|
55
|
+
fixture_set_names = Array(fixture_set_names || fixture_table_names)
|
56
|
+
methods = Module.new do
|
57
|
+
fixture_set_names.each do |fs_name|
|
58
|
+
fs_name = fs_name.to_s
|
59
|
+
accessor_name = fs_name.tr("/", "_").to_sym
|
60
|
+
|
61
|
+
define_method(accessor_name) do |*fixture_names|
|
62
|
+
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
63
|
+
return_single_record = fixture_names.size == 1
|
64
|
+
fixture_names = @loaded_fixtures[fs_name].fixtures.keys if fixture_names.empty?
|
65
|
+
|
66
|
+
@fixture_cache[fs_name] ||= {}
|
67
|
+
|
68
|
+
instances = fixture_names.map do |f_name|
|
69
|
+
f_name = f_name.to_s if f_name.is_a?(Symbol)
|
70
|
+
@fixture_cache[fs_name].delete(f_name) if force_reload
|
71
|
+
|
72
|
+
if @loaded_fixtures[fs_name][f_name]
|
73
|
+
@fixture_cache[fs_name][f_name] ||= @loaded_fixtures[fs_name][f_name].find
|
74
|
+
else
|
75
|
+
raise StandardError, "No fixture named '#{f_name}' found for fixture set '#{fs_name}'"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
return_single_record ? instances.first : instances
|
80
|
+
end
|
81
|
+
private accessor_name
|
82
|
+
end
|
83
|
+
end
|
84
|
+
include methods
|
85
|
+
end
|
86
|
+
|
87
|
+
def uses_transaction(*methods)
|
88
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
89
|
+
@uses_transaction.concat methods.map(&:to_s)
|
90
|
+
end
|
91
|
+
|
92
|
+
def uses_transaction?(method)
|
93
|
+
@uses_transaction = [] unless defined?(@uses_transaction)
|
94
|
+
@uses_transaction.include?(method.to_s)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def run_in_transaction?
|
99
|
+
use_transactional_tests &&
|
100
|
+
!self.class.uses_transaction?(method_name)
|
101
|
+
end
|
102
|
+
|
103
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
104
|
+
if pre_loaded_fixtures && !use_transactional_tests
|
105
|
+
raise RuntimeError, "pre_loaded_fixtures requires use_transactional_tests"
|
106
|
+
end
|
107
|
+
|
108
|
+
@fixture_cache = {}
|
109
|
+
@fixture_connections = []
|
110
|
+
@@already_loaded_fixtures ||= {}
|
111
|
+
@connection_subscriber = nil
|
112
|
+
|
113
|
+
# Load fixtures once and begin transaction.
|
114
|
+
if run_in_transaction?
|
115
|
+
@saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
|
116
|
+
|
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
|
+
setup_shared_connection_pool
|
135
|
+
|
136
|
+
if spec_name
|
137
|
+
begin
|
138
|
+
connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
|
139
|
+
rescue ConnectionNotEstablished
|
140
|
+
connection = nil
|
141
|
+
end
|
142
|
+
|
143
|
+
if connection && !@fixture_connections.include?(connection)
|
144
|
+
connection.begin_transaction joinable: false, _lazy: false
|
145
|
+
connection.pool.lock_thread = true if lock_threads
|
146
|
+
@fixture_connections << connection
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Load fixtures for every test.
|
152
|
+
else
|
153
|
+
ActiveRecord::FixtureSet.reset_cache
|
154
|
+
@@already_loaded_fixtures[self.class] = nil
|
155
|
+
@loaded_fixtures = load_fixtures(config)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Instantiate fixtures for every test if requested.
|
159
|
+
instantiate_fixtures if use_instantiated_fixtures
|
160
|
+
end
|
161
|
+
|
162
|
+
def teardown_fixtures
|
163
|
+
# Rollback changes if a transaction is active.
|
164
|
+
if run_in_transaction?
|
165
|
+
ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber
|
166
|
+
@fixture_connections.each do |connection|
|
167
|
+
connection.rollback_transaction if connection.transaction_open?
|
168
|
+
connection.pool.lock_thread = false
|
169
|
+
end
|
170
|
+
@fixture_connections.clear
|
171
|
+
teardown_shared_connection_pool
|
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
|
+
writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
|
194
|
+
|
195
|
+
ActiveRecord::Base.connection_handlers.values.each do |handler|
|
196
|
+
if handler != writing_handler
|
197
|
+
handler.connection_pool_list.each do |pool|
|
198
|
+
name = pool.spec.name
|
199
|
+
writing_connection = writing_handler.retrieve_connection_pool(name)
|
200
|
+
return unless writing_connection
|
201
|
+
|
202
|
+
reading_connection = handler.send(:owner_to_pool)[name]
|
203
|
+
next if reading_connection == writing_connection
|
204
|
+
|
205
|
+
@saved_pool_configs[handler][name] = reading_connection
|
206
|
+
handler.send(:owner_to_pool)[name] = writing_connection
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
def teardown_shared_connection_pool
|
213
|
+
@saved_pool_configs.each_pair do |handler, pools|
|
214
|
+
pools.each_pair do |name, pool|
|
215
|
+
handler.send(:owner_to_pool)[name] = pool
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
@saved_pool_configs.clear
|
220
|
+
end
|
221
|
+
|
222
|
+
def load_fixtures(config)
|
223
|
+
fixtures = ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config)
|
224
|
+
Hash[fixtures.map { |f| [f.name, f] }]
|
225
|
+
end
|
226
|
+
|
227
|
+
def instantiate_fixtures
|
228
|
+
if pre_loaded_fixtures
|
229
|
+
raise RuntimeError, "Load fixtures before instantiating them." if ActiveRecord::FixtureSet.all_loaded_fixtures.empty?
|
230
|
+
ActiveRecord::FixtureSet.instantiate_all_loaded_fixtures(self, load_instances?)
|
231
|
+
else
|
232
|
+
raise RuntimeError, "Load fixtures before instantiating them." if @loaded_fixtures.nil?
|
233
|
+
@loaded_fixtures.each_value do |fixture_set|
|
234
|
+
ActiveRecord::FixtureSet.instantiate_fixtures(self, fixture_set, load_instances?)
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def load_instances?
|
240
|
+
use_instantiated_fixtures != :no_instances
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|
@@ -56,23 +56,29 @@ 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
83
|
["created_at", "created_on"]
|
78
84
|
end
|
@@ -81,13 +87,15 @@ module ActiveRecord
|
|
81
87
|
["updated_at", "updated_on"]
|
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
|
@@ -102,8 +110,8 @@ module ActiveRecord
|
|
102
110
|
super
|
103
111
|
end
|
104
112
|
|
105
|
-
def _update_record
|
106
|
-
if
|
113
|
+
def _update_record
|
114
|
+
if @_touch_record && should_record_timestamps?
|
107
115
|
current_time = current_time_from_proper_timezone
|
108
116
|
|
109
117
|
timestamp_attributes_for_update_in_model.each do |column|
|
@@ -111,7 +119,13 @@ module ActiveRecord
|
|
111
119
|
_write_attribute(column, current_time)
|
112
120
|
end
|
113
121
|
end
|
114
|
-
|
122
|
+
|
123
|
+
super
|
124
|
+
end
|
125
|
+
|
126
|
+
def create_or_update(touch: true, **)
|
127
|
+
@_touch_record = touch
|
128
|
+
super
|
115
129
|
end
|
116
130
|
|
117
131
|
def should_record_timestamps?
|
@@ -119,26 +133,25 @@ module ActiveRecord
|
|
119
133
|
end
|
120
134
|
|
121
135
|
def timestamp_attributes_for_create_in_model
|
122
|
-
self.class.
|
136
|
+
self.class.timestamp_attributes_for_create_in_model
|
123
137
|
end
|
124
138
|
|
125
139
|
def timestamp_attributes_for_update_in_model
|
126
|
-
self.class.
|
140
|
+
self.class.timestamp_attributes_for_update_in_model
|
127
141
|
end
|
128
142
|
|
129
143
|
def all_timestamp_attributes_in_model
|
130
|
-
self.class.
|
144
|
+
self.class.all_timestamp_attributes_in_model
|
131
145
|
end
|
132
146
|
|
133
147
|
def current_time_from_proper_timezone
|
134
|
-
self.class.
|
148
|
+
self.class.current_time_from_proper_timezone
|
135
149
|
end
|
136
150
|
|
137
|
-
def max_updated_column_timestamp
|
138
|
-
|
139
|
-
.map { |attr| self[attr] }
|
151
|
+
def max_updated_column_timestamp
|
152
|
+
timestamp_attributes_for_update_in_model
|
153
|
+
.map { |attr| self[attr]&.to_time }
|
140
154
|
.compact
|
141
|
-
.map(&:to_time)
|
142
155
|
.max
|
143
156
|
end
|
144
157
|
|
@@ -2,14 +2,14 @@
|
|
2
2
|
|
3
3
|
module ActiveRecord
|
4
4
|
# = Active Record Touch Later
|
5
|
-
module TouchLater
|
5
|
+
module TouchLater # :nodoc:
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
9
|
before_commit_without_transaction_enrollment :touch_deferred_attributes
|
10
10
|
end
|
11
11
|
|
12
|
-
def touch_later(*names) # :nodoc:
|
12
|
+
def touch_later(*names, **) # :nodoc:
|
13
13
|
unless persisted?
|
14
14
|
raise ActiveRecordError, <<-MSG.squish
|
15
15
|
cannot touch on a new or destroyed record object. Consider using
|
@@ -22,7 +22,8 @@ module ActiveRecord
|
|
22
22
|
@_touch_time = current_time_from_proper_timezone
|
23
23
|
|
24
24
|
surreptitiously_touch @_defer_touch_attrs
|
25
|
-
|
25
|
+
add_to_transaction
|
26
|
+
@_new_record_before_last_commit ||= false
|
26
27
|
|
27
28
|
# touch the parents as we are not calling the after_save callbacks
|
28
29
|
self.class.reflect_on_all_associations(:belongs_to).each do |r|
|
@@ -40,7 +41,6 @@ module ActiveRecord
|
|
40
41
|
end
|
41
42
|
|
42
43
|
private
|
43
|
-
|
44
44
|
def surreptitiously_touch(attrs)
|
45
45
|
attrs.each { |attr| write_attribute attr, @_touch_time }
|
46
46
|
clear_attribute_changes attrs
|
@@ -48,6 +48,7 @@ module ActiveRecord
|
|
48
48
|
|
49
49
|
def touch_deferred_attributes
|
50
50
|
if has_defer_touch_attrs? && persisted?
|
51
|
+
@_skip_dirty_tracking = true
|
51
52
|
touch(*@_defer_touch_attrs, time: @_touch_time)
|
52
53
|
@_defer_touch_attrs, @_touch_time = nil, nil
|
53
54
|
end
|