activerecord 6.0.6.1 → 6.1.7.4

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.
Files changed (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1143 -780
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_record/aggregations.rb +5 -5
  6. data/lib/active_record/association_relation.rb +30 -12
  7. data/lib/active_record/associations/alias_tracker.rb +19 -15
  8. data/lib/active_record/associations/association.rb +49 -26
  9. data/lib/active_record/associations/association_scope.rb +18 -20
  10. data/lib/active_record/associations/belongs_to_association.rb +23 -10
  11. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -3
  12. data/lib/active_record/associations/builder/association.rb +32 -5
  13. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  14. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  15. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  16. data/lib/active_record/associations/builder/has_many.rb +6 -2
  17. data/lib/active_record/associations/builder/has_one.rb +11 -14
  18. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  19. data/lib/active_record/associations/collection_association.rb +32 -18
  20. data/lib/active_record/associations/collection_proxy.rb +12 -5
  21. data/lib/active_record/associations/foreign_association.rb +13 -0
  22. data/lib/active_record/associations/has_many_association.rb +24 -2
  23. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  24. data/lib/active_record/associations/has_one_association.rb +15 -1
  25. data/lib/active_record/associations/join_dependency/join_association.rb +37 -21
  26. data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
  27. data/lib/active_record/associations/join_dependency.rb +63 -49
  28. data/lib/active_record/associations/preloader/association.rb +14 -8
  29. data/lib/active_record/associations/preloader/through_association.rb +1 -1
  30. data/lib/active_record/associations/preloader.rb +5 -3
  31. data/lib/active_record/associations/singular_association.rb +1 -1
  32. data/lib/active_record/associations.rb +118 -11
  33. data/lib/active_record/attribute_assignment.rb +10 -8
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  35. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  36. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  37. data/lib/active_record/attribute_methods/query.rb +3 -6
  38. data/lib/active_record/attribute_methods/read.rb +8 -11
  39. data/lib/active_record/attribute_methods/serialization.rb +11 -5
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  41. data/lib/active_record/attribute_methods/write.rb +12 -20
  42. data/lib/active_record/attribute_methods.rb +64 -54
  43. data/lib/active_record/attributes.rb +33 -8
  44. data/lib/active_record/autosave_association.rb +47 -30
  45. data/lib/active_record/base.rb +2 -14
  46. data/lib/active_record/callbacks.rb +152 -22
  47. data/lib/active_record/coders/yaml_column.rb +1 -1
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +185 -134
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +66 -23
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +3 -8
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  53. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +114 -26
  56. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +228 -83
  58. data/lib/active_record/connection_adapters/abstract/transaction.rb +92 -33
  59. data/lib/active_record/connection_adapters/abstract_adapter.rb +52 -76
  60. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +123 -87
  61. data/lib/active_record/connection_adapters/column.rb +15 -1
  62. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  63. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +35 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +24 -24
  65. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  66. data/lib/active_record/connection_adapters/mysql/quoting.rb +18 -3
  67. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  69. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +5 -2
  70. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +7 -4
  71. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  72. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  73. data/lib/active_record/connection_adapters/pool_config.rb +73 -0
  74. data/lib/active_record/connection_adapters/pool_manager.rb +47 -0
  75. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  76. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +14 -53
  77. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  78. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  79. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -2
  80. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  85. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/quoting.rb +30 -4
  87. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  88. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  89. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  90. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  91. data/lib/active_record/connection_adapters/postgresql_adapter.rb +75 -64
  92. data/lib/active_record/connection_adapters/schema_cache.rb +130 -15
  93. data/lib/active_record/connection_adapters/sql_type_metadata.rb +8 -0
  94. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +32 -5
  95. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  96. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  97. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +36 -3
  98. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +48 -50
  99. data/lib/active_record/connection_adapters.rb +52 -0
  100. data/lib/active_record/connection_handling.rb +218 -71
  101. data/lib/active_record/core.rb +264 -63
  102. data/lib/active_record/database_configurations/connection_url_resolver.rb +99 -0
  103. data/lib/active_record/database_configurations/database_config.rb +52 -9
  104. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  105. data/lib/active_record/database_configurations/url_config.rb +15 -40
  106. data/lib/active_record/database_configurations.rb +125 -85
  107. data/lib/active_record/delegated_type.rb +209 -0
  108. data/lib/active_record/destroy_association_async_job.rb +36 -0
  109. data/lib/active_record/enum.rb +69 -34
  110. data/lib/active_record/errors.rb +47 -12
  111. data/lib/active_record/explain.rb +9 -4
  112. data/lib/active_record/explain_subscriber.rb +1 -1
  113. data/lib/active_record/fixture_set/file.rb +10 -17
  114. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  115. data/lib/active_record/fixture_set/render_context.rb +1 -1
  116. data/lib/active_record/fixture_set/table_row.rb +2 -2
  117. data/lib/active_record/fixtures.rb +58 -9
  118. data/lib/active_record/gem_version.rb +3 -3
  119. data/lib/active_record/inheritance.rb +40 -18
  120. data/lib/active_record/insert_all.rb +38 -5
  121. data/lib/active_record/integration.rb +3 -5
  122. data/lib/active_record/internal_metadata.rb +18 -7
  123. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  124. data/lib/active_record/locking/optimistic.rb +24 -17
  125. data/lib/active_record/locking/pessimistic.rb +6 -2
  126. data/lib/active_record/log_subscriber.rb +27 -8
  127. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  128. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  129. data/lib/active_record/middleware/database_selector.rb +4 -1
  130. data/lib/active_record/migration/command_recorder.rb +47 -27
  131. data/lib/active_record/migration/compatibility.rb +72 -18
  132. data/lib/active_record/migration.rb +114 -84
  133. data/lib/active_record/model_schema.rb +89 -14
  134. data/lib/active_record/nested_attributes.rb +2 -3
  135. data/lib/active_record/no_touching.rb +1 -1
  136. data/lib/active_record/persistence.rb +50 -45
  137. data/lib/active_record/query_cache.rb +15 -5
  138. data/lib/active_record/querying.rb +11 -6
  139. data/lib/active_record/railtie.rb +64 -44
  140. data/lib/active_record/railties/console_sandbox.rb +2 -4
  141. data/lib/active_record/railties/databases.rake +279 -101
  142. data/lib/active_record/readonly_attributes.rb +4 -0
  143. data/lib/active_record/reflection.rb +60 -44
  144. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  145. data/lib/active_record/relation/batches.rb +38 -31
  146. data/lib/active_record/relation/calculations.rb +104 -43
  147. data/lib/active_record/relation/finder_methods.rb +44 -14
  148. data/lib/active_record/relation/from_clause.rb +1 -1
  149. data/lib/active_record/relation/merger.rb +20 -23
  150. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  151. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  152. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +10 -6
  153. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  154. data/lib/active_record/relation/predicate_builder.rb +61 -38
  155. data/lib/active_record/relation/query_methods.rb +322 -196
  156. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  157. data/lib/active_record/relation/spawn_methods.rb +8 -7
  158. data/lib/active_record/relation/where_clause.rb +111 -61
  159. data/lib/active_record/relation.rb +100 -81
  160. data/lib/active_record/result.rb +41 -33
  161. data/lib/active_record/runtime_registry.rb +2 -2
  162. data/lib/active_record/sanitization.rb +6 -17
  163. data/lib/active_record/schema_dumper.rb +34 -4
  164. data/lib/active_record/schema_migration.rb +2 -8
  165. data/lib/active_record/scoping/default.rb +1 -3
  166. data/lib/active_record/scoping/named.rb +1 -17
  167. data/lib/active_record/secure_token.rb +16 -8
  168. data/lib/active_record/serialization.rb +5 -3
  169. data/lib/active_record/signed_id.rb +116 -0
  170. data/lib/active_record/statement_cache.rb +20 -4
  171. data/lib/active_record/store.rb +8 -3
  172. data/lib/active_record/suppressor.rb +2 -2
  173. data/lib/active_record/table_metadata.rb +42 -51
  174. data/lib/active_record/tasks/database_tasks.rb +140 -113
  175. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  176. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  177. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  178. data/lib/active_record/test_databases.rb +5 -4
  179. data/lib/active_record/test_fixtures.rb +79 -31
  180. data/lib/active_record/timestamp.rb +4 -6
  181. data/lib/active_record/touch_later.rb +21 -21
  182. data/lib/active_record/transactions.rb +19 -66
  183. data/lib/active_record/type/serialized.rb +6 -2
  184. data/lib/active_record/type.rb +8 -1
  185. data/lib/active_record/type_caster/connection.rb +0 -1
  186. data/lib/active_record/type_caster/map.rb +8 -5
  187. data/lib/active_record/validations/associated.rb +1 -1
  188. data/lib/active_record/validations/numericality.rb +35 -0
  189. data/lib/active_record/validations/uniqueness.rb +24 -4
  190. data/lib/active_record/validations.rb +1 -0
  191. data/lib/active_record.rb +7 -14
  192. data/lib/arel/attributes/attribute.rb +4 -0
  193. data/lib/arel/collectors/bind.rb +5 -0
  194. data/lib/arel/collectors/composite.rb +8 -0
  195. data/lib/arel/collectors/sql_string.rb +7 -0
  196. data/lib/arel/collectors/substitute_binds.rb +7 -0
  197. data/lib/arel/nodes/binary.rb +82 -8
  198. data/lib/arel/nodes/bind_param.rb +8 -0
  199. data/lib/arel/nodes/casted.rb +21 -9
  200. data/lib/arel/nodes/equality.rb +6 -9
  201. data/lib/arel/nodes/grouping.rb +3 -0
  202. data/lib/arel/nodes/homogeneous_in.rb +76 -0
  203. data/lib/arel/nodes/in.rb +8 -1
  204. data/lib/arel/nodes/infix_operation.rb +13 -1
  205. data/lib/arel/nodes/join_source.rb +1 -1
  206. data/lib/arel/nodes/node.rb +7 -6
  207. data/lib/arel/nodes/ordering.rb +27 -0
  208. data/lib/arel/nodes/sql_literal.rb +3 -0
  209. data/lib/arel/nodes/table_alias.rb +7 -3
  210. data/lib/arel/nodes/unary.rb +0 -1
  211. data/lib/arel/nodes.rb +3 -1
  212. data/lib/arel/predications.rb +12 -18
  213. data/lib/arel/select_manager.rb +1 -2
  214. data/lib/arel/table.rb +13 -5
  215. data/lib/arel/visitors/dot.rb +14 -2
  216. data/lib/arel/visitors/mysql.rb +11 -1
  217. data/lib/arel/visitors/postgresql.rb +15 -4
  218. data/lib/arel/visitors/to_sql.rb +89 -78
  219. data/lib/arel/visitors.rb +0 -7
  220. data/lib/arel.rb +5 -13
  221. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  222. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  223. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  224. data/lib/rails/generators/active_record/migration.rb +6 -1
  225. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  226. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  227. metadata +25 -26
  228. data/lib/active_record/advisory_lock_base.rb +0 -18
  229. data/lib/active_record/attribute_decorators.rb +0 -88
  230. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  231. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  232. data/lib/active_record/define_callbacks.rb +0 -22
  233. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  234. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  235. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  236. data/lib/arel/attributes.rb +0 -22
  237. data/lib/arel/visitors/depth_first.rb +0 -203
  238. data/lib/arel/visitors/ibm_db.rb +0 -34
  239. data/lib/arel/visitors/informix.rb +0 -62
  240. data/lib/arel/visitors/mssql.rb +0 -156
  241. data/lib/arel/visitors/oracle.rb +0 -158
  242. data/lib/arel/visitors/oracle12.rb +0 -65
  243. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -12,26 +12,24 @@ module ActiveRecord
12
12
  delegate :connection, :establish_connection, :clear_active_connections!,
13
13
  to: ActiveRecord::Base
14
14
 
15
- def initialize(configuration)
16
- @configuration = configuration
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 configuration["database"],
22
- configuration.merge("encoding" => encoding)
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 configuration["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
- configuration["schema_search_path"]
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 = ["-s", "-x", "-O", "-f", filename]
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 << configuration["database"]
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,31 +80,31 @@ module ActiveRecord
82
80
 
83
81
  def structure_load(filename, extra_flags)
84
82
  set_psql_env
85
- args = ["-v", ON_ERROR_STOP_1, "-q", "-X", "-f", filename]
83
+ args = ["--set", ON_ERROR_STOP_1, "--quiet", "--no-psqlrc", "--file", filename]
86
84
  args.concat(Array(extra_flags)) if extra_flags
87
- args << configuration["database"]
85
+ args << db_config.database
88
86
  run_cmd("psql", args, "loading")
89
87
  end
90
88
 
91
89
  private
92
- attr_reader :configuration
90
+ attr_reader :db_config, :configuration_hash
93
91
 
94
92
  def encoding
95
- configuration["encoding"] || DEFAULT_ENCODING
93
+ configuration_hash[:encoding] || DEFAULT_ENCODING
96
94
  end
97
95
 
98
96
  def establish_master_connection
99
- establish_connection configuration.merge(
100
- "database" => "postgres",
101
- "schema_search_path" => "public"
97
+ establish_connection configuration_hash.merge(
98
+ database: "postgres",
99
+ schema_search_path: "public"
102
100
  )
103
101
  end
104
102
 
105
103
  def set_psql_env
106
- ENV["PGHOST"] = configuration["host"] if configuration["host"]
107
- ENV["PGPORT"] = configuration["port"].to_s if configuration["port"]
108
- ENV["PGPASSWORD"] = configuration["password"].to_s if configuration["password"]
109
- ENV["PGUSER"] = configuration["username"].to_s if configuration["username"]
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]
110
108
  end
111
109
 
112
110
  def run_cmd(cmd, args, action)
@@ -5,20 +5,25 @@ module ActiveRecord
5
5
  class SQLiteDatabaseTasks # :nodoc:
6
6
  delegate :connection, :establish_connection, to: ActiveRecord::Base
7
7
 
8
- def initialize(configuration, root = ActiveRecord::Tasks::DatabaseTasks.root)
9
- @configuration, @root = configuration, root
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?(configuration["database"])
18
+ raise DatabaseAlreadyExists if File.exist?(db_config.database)
14
19
 
15
- establish_connection configuration
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 configuration["database"]
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 << configuration["database"]
48
+ args << db_config.database
44
49
 
45
50
  ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
46
51
  if ignore_tables.any?
@@ -53,13 +58,12 @@ 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} #{dbfile} < "#{filename}"`
62
+ `sqlite3 #{flags} #{db_config.database} < "#{filename}"`
59
63
  end
60
64
 
61
65
  private
62
- attr_reader :configuration, :root
66
+ attr_reader :db_config, :root
63
67
 
64
68
  def run_cmd(cmd, args, out)
65
69
  fail run_cmd_error(cmd, args) unless Kernel.system(cmd, *args, out: out)
@@ -5,18 +5,19 @@ require "active_support/testing/parallelization"
5
5
  module ActiveRecord
6
6
  module TestDatabases # :nodoc:
7
7
  ActiveSupport::Testing::Parallelization.after_fork_hook do |i|
8
- create_and_load_schema(i, env_name: Rails.env)
8
+ create_and_load_schema(i, env_name: ActiveRecord::ConnectionHandling::DEFAULT_ENV.call)
9
9
  end
10
10
 
11
11
  def self.create_and_load_schema(i, env_name:)
12
12
  old, ENV["VERBOSE"] = ENV["VERBOSE"], "false"
13
13
 
14
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)
15
+ db_config._database = "#{db_config.database}-#{i}"
16
+
17
+ ActiveRecord::Tasks::DatabaseTasks.reconstruct_from_schema(db_config, ActiveRecord::Base.schema_format, nil)
17
18
  end
18
19
  ensure
19
- ActiveRecord::Base.establish_connection(Rails.env.to_sym)
20
+ ActiveRecord::Base.establish_connection
20
21
  ENV["VERBOSE"] = old
21
22
  end
22
23
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/enumerable"
4
+
3
5
  module ActiveRecord
4
6
  module TestFixtures
5
7
  extend ActiveSupport::Concern
@@ -21,7 +23,6 @@ module ActiveRecord
21
23
  class_attribute :use_transactional_tests, default: true
22
24
  class_attribute :use_instantiated_fixtures, default: false # true, false, or :no_instances
23
25
  class_attribute :pre_loaded_fixtures, default: false
24
- class_attribute :config, default: ActiveRecord::Base
25
26
  class_attribute :lock_threads, default: true
26
27
  end
27
28
 
@@ -41,8 +42,9 @@ module ActiveRecord
41
42
  def fixtures(*fixture_set_names)
42
43
  if fixture_set_names.first == :all
43
44
  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] }
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("/") }
46
48
  else
47
49
  fixture_set_names = fixture_set_names.flatten.map(&:to_s)
48
50
  end
@@ -97,7 +99,7 @@ module ActiveRecord
97
99
 
98
100
  def run_in_transaction?
99
101
  use_transactional_tests &&
100
- !self.class.uses_transaction?(method_name)
102
+ !self.class.uses_transaction?(name)
101
103
  end
102
104
 
103
105
  def setup_fixtures(config = ActiveRecord::Base)
@@ -109,11 +111,11 @@ module ActiveRecord
109
111
  @fixture_connections = []
110
112
  @@already_loaded_fixtures ||= {}
111
113
  @connection_subscriber = nil
114
+ @legacy_saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
115
+ @saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
112
116
 
113
117
  # Load fixtures once and begin transaction.
114
118
  if run_in_transaction?
115
- @saved_pool_configs = Hash.new { |hash, key| hash[key] = {} }
116
-
117
119
  if @@already_loaded_fixtures[self.class]
118
120
  @loaded_fixtures = @@already_loaded_fixtures[self.class]
119
121
  else
@@ -131,19 +133,24 @@ module ActiveRecord
131
133
  # When connections are established in the future, begin a transaction too
132
134
  @connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
133
135
  spec_name = payload[:spec_name] if payload.key?(:spec_name)
134
- setup_shared_connection_pool
136
+ shard = payload[:shard] if payload.key?(:shard)
137
+ setup_shared_connection_pool if ActiveRecord::Base.legacy_connection_handling
135
138
 
136
139
  if spec_name
137
140
  begin
138
- connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
141
+ connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name, shard: shard)
139
142
  rescue ConnectionNotEstablished
140
143
  connection = nil
141
144
  end
142
145
 
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
146
+ if connection
147
+ setup_shared_connection_pool unless ActiveRecord::Base.legacy_connection_handling
148
+
149
+ if !@fixture_connections.include?(connection)
150
+ connection.begin_transaction joinable: false, _lazy: false
151
+ connection.pool.lock_thread = true if lock_threads
152
+ @fixture_connections << connection
153
+ end
147
154
  end
148
155
  end
149
156
  end
@@ -190,38 +197,79 @@ module ActiveRecord
190
197
  # need to share a connection pool so that the reading connection
191
198
  # can see data in the open transaction on the writing connection.
192
199
  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
200
+ if ActiveRecord::Base.legacy_connection_handling
201
+ writing_handler = ActiveRecord::Base.connection_handlers[ActiveRecord::Base.writing_role]
202
+
203
+ ActiveRecord::Base.connection_handlers.values.each do |handler|
204
+ if handler != writing_handler
205
+ handler.connection_pool_names.each do |name|
206
+ writing_pool_manager = writing_handler.send(:owner_to_pool_manager)[name]
207
+ return unless writing_pool_manager
208
+
209
+ pool_manager = handler.send(:owner_to_pool_manager)[name]
210
+ @legacy_saved_pool_configs[handler][name] ||= {}
211
+ pool_manager.shard_names.each do |shard_name|
212
+ writing_pool_config = writing_pool_manager.get_pool_config(nil, shard_name)
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
207
237
  end
208
238
  end
209
239
  end
210
240
  end
211
241
 
212
242
  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
243
+ if ActiveRecord::Base.legacy_connection_handling
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
254
+
255
+ @saved_pool_configs.each_pair do |name, shards|
256
+ pool_manager = handler.send(:owner_to_pool_manager)[name]
257
+ shards.each_pair do |shard_name, roles|
258
+ roles.each_pair do |role, pool_config|
259
+ next unless pool_manager.get_pool_config(role, shard_name)
260
+
261
+ pool_manager.set_pool_config(role, shard_name, pool_config)
262
+ end
263
+ end
216
264
  end
217
265
  end
218
266
 
267
+ @legacy_saved_pool_configs.clear
219
268
  @saved_pool_configs.clear
220
269
  end
221
270
 
222
271
  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] }]
272
+ ActiveRecord::FixtureSet.create_fixtures(fixture_path, fixture_table_names, fixture_class_names, config).index_by(&:name)
225
273
  end
226
274
 
227
275
  def instantiate_fixtures
@@ -80,11 +80,11 @@ module ActiveRecord
80
80
 
81
81
  private
82
82
  def timestamp_attributes_for_create
83
- ["created_at", "created_on"]
83
+ ["created_at", "created_on"].map! { |name| attribute_aliases[name] || name }
84
84
  end
85
85
 
86
86
  def timestamp_attributes_for_update
87
- ["updated_at", "updated_on"]
87
+ ["updated_at", "updated_on"].map! { |name| attribute_aliases[name] || name }
88
88
  end
89
89
 
90
90
  def reload_schema_from_cache
@@ -101,9 +101,7 @@ module ActiveRecord
101
101
  current_time = current_time_from_proper_timezone
102
102
 
103
103
  all_timestamp_attributes_in_model.each do |column|
104
- if !attribute_present?(column)
105
- _write_attribute(column, current_time)
106
- end
104
+ _write_attribute(column, current_time) unless _read_attribute(column)
107
105
  end
108
106
  end
109
107
 
@@ -159,7 +157,7 @@ module ActiveRecord
159
157
  def clear_timestamp_attributes
160
158
  all_timestamp_attributes_in_model.each do |attribute_name|
161
159
  self[attribute_name] = nil
162
- clear_attribute_changes([attribute_name])
160
+ clear_attribute_change(attribute_name)
163
161
  end
164
162
  end
165
163
  end
@@ -3,22 +3,20 @@
3
3
  module ActiveRecord
4
4
  # = Active Record Touch Later
5
5
  module TouchLater # :nodoc:
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- before_commit_without_transaction_enrollment :touch_deferred_attributes
6
+ def before_committed!
7
+ touch_deferred_attributes if has_defer_touch_attrs? && persisted?
8
+ super
10
9
  end
11
10
 
12
- 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
11
+ def touch_later(*names) # :nodoc:
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
@@ -36,22 +34,24 @@ module ActiveRecord
36
34
  def touch(*names, time: nil) # :nodoc:
37
35
  if has_defer_touch_attrs?
38
36
  names |= @_defer_touch_attrs
37
+ super(*names, time: time)
38
+ @_defer_touch_attrs, @_touch_time = nil, nil
39
+ else
40
+ super
39
41
  end
40
- super(*names, time: time)
41
42
  end
42
43
 
43
44
  private
44
- def surreptitiously_touch(attrs)
45
- attrs.each { |attr| write_attribute attr, @_touch_time }
46
- clear_attribute_changes attrs
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
- if has_defer_touch_attrs? && persisted?
51
- @_skip_dirty_tracking = true
52
- touch(*@_defer_touch_attrs, time: @_touch_time)
53
- @_defer_touch_attrs, @_touch_time = nil, nil
54
- end
53
+ @_skip_dirty_tracking = true
54
+ touch(time: @_touch_time)
55
55
  end
56
56
 
57
57
  def has_defer_touch_attrs?
@@ -10,9 +10,6 @@ module ActiveRecord
10
10
  included do
11
11
  define_callbacks :commit, :rollback,
12
12
  :before_commit,
13
- :before_commit_without_transaction_enrollment,
14
- :commit_without_transaction_enrollment,
15
- :rollback_without_transaction_enrollment,
16
13
  scope: [:kind, :name]
17
14
  end
18
15
 
@@ -164,13 +161,13 @@ module ActiveRecord
164
161
  # end
165
162
  # end
166
163
  #
167
- # only "Kotori" is created. This works on MySQL and PostgreSQL. SQLite3 version >= '3.6.8' also supports it.
164
+ # only "Kotori" is created.
168
165
  #
169
166
  # Most databases don't support true nested transactions. At the time of
170
167
  # writing, the only database that we're aware of that supports true nested
171
168
  # transactions, is MS-SQL. Because of this, Active Record emulates nested
172
- # transactions by using savepoints on MySQL and PostgreSQL. See
173
- # https://dev.mysql.com/doc/refman/5.7/en/savepoint.html
169
+ # transactions by using savepoints. See
170
+ # https://dev.mysql.com/doc/refman/en/savepoint.html
174
171
  # for more information about savepoints.
175
172
  #
176
173
  # === \Callbacks
@@ -266,21 +263,6 @@ module ActiveRecord
266
263
  set_callback(:rollback, :after, *args, &block)
267
264
  end
268
265
 
269
- def before_commit_without_transaction_enrollment(*args, &block) # :nodoc:
270
- set_options_for_callbacks!(args)
271
- set_callback(:before_commit_without_transaction_enrollment, :before, *args, &block)
272
- end
273
-
274
- def after_commit_without_transaction_enrollment(*args, &block) # :nodoc:
275
- set_options_for_callbacks!(args)
276
- set_callback(:commit_without_transaction_enrollment, :after, *args, &block)
277
- end
278
-
279
- def after_rollback_without_transaction_enrollment(*args, &block) # :nodoc:
280
- set_options_for_callbacks!(args)
281
- set_callback(:rollback_without_transaction_enrollment, :after, *args, &block)
282
- end
283
-
284
266
  private
285
267
  def set_options_for_callbacks!(args, enforced_options = {})
286
268
  options = args.extract_options!.merge!(enforced_options)
@@ -289,8 +271,10 @@ module ActiveRecord
289
271
  if options[:on]
290
272
  fire_on = Array(options[:on])
291
273
  assert_valid_transaction_action(fire_on)
292
- options[:if] = Array(options[:if])
293
- options[:if].unshift(-> { transaction_include_any_action?(fire_on) })
274
+ options[:if] = [
275
+ -> { transaction_include_any_action?(fire_on) },
276
+ *options[:if]
277
+ ]
294
278
  end
295
279
  end
296
280
 
@@ -302,7 +286,7 @@ module ActiveRecord
302
286
  end
303
287
 
304
288
  # See ActiveRecord::Transactions::ClassMethods for detailed documentation.
305
- def transaction(options = {}, &block)
289
+ def transaction(**options, &block)
306
290
  self.class.transaction(**options, &block)
307
291
  end
308
292
 
@@ -310,11 +294,11 @@ module ActiveRecord
310
294
  with_transaction_returning_status { super }
311
295
  end
312
296
 
313
- def save(*, **) #:nodoc:
297
+ def save(**) #:nodoc:
314
298
  with_transaction_returning_status { super }
315
299
  end
316
300
 
317
- def save!(*, **) #:nodoc:
301
+ def save!(**) #:nodoc:
318
302
  with_transaction_returning_status { super }
319
303
  end
320
304
 
@@ -323,7 +307,6 @@ module ActiveRecord
323
307
  end
324
308
 
325
309
  def before_committed! # :nodoc:
326
- _run_before_commit_without_transaction_enrollment_callbacks
327
310
  _run_before_commit_callbacks
328
311
  end
329
312
 
@@ -335,7 +318,6 @@ module ActiveRecord
335
318
  force_clear_transaction_record_state
336
319
  if should_run_callbacks
337
320
  @_committed_already_called = true
338
- _run_commit_without_transaction_enrollment_callbacks
339
321
  _run_commit_callbacks
340
322
  end
341
323
  ensure
@@ -347,7 +329,6 @@ module ActiveRecord
347
329
  def rolledback!(force_restore_state: false, should_run_callbacks: true) #:nodoc:
348
330
  if should_run_callbacks
349
331
  _run_rollback_callbacks
350
- _run_rollback_without_transaction_enrollment_callbacks
351
332
  end
352
333
  ensure
353
334
  restore_transaction_record_state(force_restore_state)
@@ -363,13 +344,11 @@ module ActiveRecord
363
344
  # instance.
364
345
  def with_transaction_returning_status
365
346
  status = nil
366
- self.class.transaction do
367
- if has_transactional_callbacks?
368
- add_to_transaction
369
- else
370
- sync_with_transaction_state if @transaction_state&.finalized?
371
- @transaction_state = self.class.connection.transaction_state
372
- end
347
+ connection = self.class.connection
348
+ ensure_finalize = !connection.transaction_open?
349
+
350
+ connection.transaction do
351
+ add_to_transaction(ensure_finalize || has_transactional_callbacks?)
373
352
  remember_transaction_record_state
374
353
 
375
354
  status = yield
@@ -391,6 +370,7 @@ module ActiveRecord
391
370
  @_start_transaction_state ||= {
392
371
  id: id,
393
372
  new_record: @new_record,
373
+ previously_new_record: @previously_new_record,
394
374
  destroyed: @destroyed,
395
375
  attributes: @attributes,
396
376
  frozen?: frozen?,
@@ -415,7 +395,6 @@ module ActiveRecord
415
395
  # Force to clear the transaction record state.
416
396
  def force_clear_transaction_record_state
417
397
  @_start_transaction_state = nil
418
- @transaction_state = nil
419
398
  end
420
399
 
421
400
  # Restore the new record state and id of a record that was previously saved by a call to save_record_state.
@@ -423,6 +402,7 @@ module ActiveRecord
423
402
  if restore_state = @_start_transaction_state
424
403
  if force_restore_state || restore_state[:level] <= 1
425
404
  @new_record = restore_state[:new_record]
405
+ @previously_new_record = restore_state[:previously_new_record]
426
406
  @destroyed = restore_state[:destroyed]
427
407
  @attributes = restore_state[:attributes].map do |attr|
428
408
  value = @attributes.fetch_value(attr.name)
@@ -455,39 +435,12 @@ module ActiveRecord
455
435
 
456
436
  # Add the record to the current transaction so that the #after_rollback and #after_commit
457
437
  # callbacks can be called.
458
- def add_to_transaction
459
- self.class.connection.add_transaction_record(self)
438
+ def add_to_transaction(ensure_finalize = true)
439
+ self.class.connection.add_transaction_record(self, ensure_finalize)
460
440
  end
461
441
 
462
442
  def has_transactional_callbacks?
463
443
  !_rollback_callbacks.empty? || !_commit_callbacks.empty? || !_before_commit_callbacks.empty?
464
444
  end
465
-
466
- # Updates the attributes on this particular Active Record object so that
467
- # if it's associated with a transaction, then the state of the Active Record
468
- # object will be updated to reflect the current state of the transaction.
469
- #
470
- # The <tt>@transaction_state</tt> variable stores the states of the associated
471
- # transaction. This relies on the fact that a transaction can only be in
472
- # one rollback or commit (otherwise a list of states would be required).
473
- # Each Active Record object inside of a transaction carries that transaction's
474
- # TransactionState.
475
- #
476
- # This method checks to see if the ActiveRecord object's state reflects
477
- # the TransactionState, and rolls back or commits the Active Record object
478
- # as appropriate.
479
- def sync_with_transaction_state
480
- if transaction_state = @transaction_state
481
- if transaction_state.fully_committed?
482
- force_clear_transaction_record_state
483
- elsif transaction_state.committed?
484
- clear_transaction_record_state
485
- elsif transaction_state.rolledback?
486
- force_restore_state = transaction_state.fully_rolledback?
487
- restore_transaction_record_state(force_restore_state)
488
- clear_transaction_record_state
489
- end
490
- end
491
- end
492
445
  end
493
446
  end
@@ -61,9 +61,13 @@ module ActiveRecord
61
61
  end
62
62
 
63
63
  def encoded(value)
64
- unless default_value?(value)
65
- coder.dump(value)
64
+ return if default_value?(value)
65
+ payload = coder.dump(value)
66
+ if payload && binary? && payload.encoding != Encoding::BINARY
67
+ payload = payload.dup if payload.frozen?
68
+ payload.force_encoding(Encoding::BINARY)
66
69
  end
70
+ payload
67
71
  end
68
72
  end
69
73
  end