activerecord 6.1.7.6 → 7.0.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.

Files changed (238) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1055 -1180
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_record/aggregations.rb +1 -1
  6. data/lib/active_record/association_relation.rb +0 -10
  7. data/lib/active_record/associations/association.rb +33 -17
  8. data/lib/active_record/associations/association_scope.rb +1 -3
  9. data/lib/active_record/associations/belongs_to_association.rb +15 -4
  10. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +10 -2
  11. data/lib/active_record/associations/builder/association.rb +8 -2
  12. data/lib/active_record/associations/builder/belongs_to.rb +19 -6
  13. data/lib/active_record/associations/builder/collection_association.rb +10 -3
  14. data/lib/active_record/associations/builder/has_many.rb +3 -2
  15. data/lib/active_record/associations/builder/has_one.rb +2 -1
  16. data/lib/active_record/associations/builder/singular_association.rb +2 -2
  17. data/lib/active_record/associations/collection_association.rb +18 -19
  18. data/lib/active_record/associations/collection_proxy.rb +8 -3
  19. data/lib/active_record/associations/disable_joins_association_scope.rb +59 -0
  20. data/lib/active_record/associations/has_many_association.rb +1 -1
  21. data/lib/active_record/associations/has_many_through_association.rb +2 -1
  22. data/lib/active_record/associations/has_one_association.rb +10 -7
  23. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  24. data/lib/active_record/associations/join_dependency.rb +6 -2
  25. data/lib/active_record/associations/preloader/association.rb +186 -52
  26. data/lib/active_record/associations/preloader/batch.rb +48 -0
  27. data/lib/active_record/associations/preloader/branch.rb +147 -0
  28. data/lib/active_record/associations/preloader/through_association.rb +49 -13
  29. data/lib/active_record/associations/preloader.rb +39 -113
  30. data/lib/active_record/associations/singular_association.rb +8 -2
  31. data/lib/active_record/associations/through_association.rb +3 -3
  32. data/lib/active_record/associations.rb +90 -82
  33. data/lib/active_record/asynchronous_queries_tracker.rb +60 -0
  34. data/lib/active_record/attribute_assignment.rb +1 -1
  35. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  36. data/lib/active_record/attribute_methods/dirty.rb +49 -16
  37. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  38. data/lib/active_record/attribute_methods/query.rb +2 -2
  39. data/lib/active_record/attribute_methods/read.rb +7 -5
  40. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  41. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  42. data/lib/active_record/attribute_methods/write.rb +7 -10
  43. data/lib/active_record/attribute_methods.rb +13 -14
  44. data/lib/active_record/attributes.rb +24 -35
  45. data/lib/active_record/autosave_association.rb +6 -21
  46. data/lib/active_record/base.rb +19 -1
  47. data/lib/active_record/callbacks.rb +2 -2
  48. data/lib/active_record/coders/yaml_column.rb +2 -14
  49. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +292 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  52. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +47 -561
  53. data/lib/active_record/connection_adapters/abstract/database_limits.rb +0 -17
  54. data/lib/active_record/connection_adapters/abstract/database_statements.rb +46 -22
  55. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  56. data/lib/active_record/connection_adapters/abstract/quoting.rb +43 -82
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +34 -13
  59. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +69 -18
  60. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -22
  61. data/lib/active_record/connection_adapters/abstract_adapter.rb +149 -74
  62. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +97 -81
  63. data/lib/active_record/connection_adapters/column.rb +4 -0
  64. data/lib/active_record/connection_adapters/mysql/database_statements.rb +35 -23
  65. data/lib/active_record/connection_adapters/mysql/quoting.rb +35 -21
  66. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  67. data/lib/active_record/connection_adapters/pool_config.rb +7 -7
  68. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -1
  69. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -12
  70. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  73. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  75. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  76. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  77. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  78. data/lib/active_record/connection_adapters/postgresql/quoting.rb +50 -76
  79. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  80. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +21 -1
  81. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +22 -1
  82. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +25 -0
  83. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +27 -16
  84. data/lib/active_record/connection_adapters/postgresql_adapter.rb +207 -107
  85. data/lib/active_record/connection_adapters/schema_cache.rb +39 -38
  86. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +25 -19
  87. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +15 -16
  88. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  89. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  90. data/lib/active_record/connection_adapters.rb +6 -5
  91. data/lib/active_record/connection_handling.rb +47 -53
  92. data/lib/active_record/core.rb +121 -146
  93. data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -1
  94. data/lib/active_record/database_configurations/database_config.rb +12 -9
  95. data/lib/active_record/database_configurations/hash_config.rb +63 -5
  96. data/lib/active_record/database_configurations/url_config.rb +2 -2
  97. data/lib/active_record/database_configurations.rb +15 -32
  98. data/lib/active_record/delegated_type.rb +52 -11
  99. data/lib/active_record/destroy_association_async_job.rb +1 -1
  100. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  101. data/lib/active_record/dynamic_matchers.rb +1 -1
  102. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  103. data/lib/active_record/encryption/cipher.rb +53 -0
  104. data/lib/active_record/encryption/config.rb +44 -0
  105. data/lib/active_record/encryption/configurable.rb +61 -0
  106. data/lib/active_record/encryption/context.rb +35 -0
  107. data/lib/active_record/encryption/contexts.rb +72 -0
  108. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  109. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  110. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  111. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  112. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  113. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  114. data/lib/active_record/encryption/encryptor.rb +155 -0
  115. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  116. data/lib/active_record/encryption/errors.rb +15 -0
  117. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  118. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +28 -0
  119. data/lib/active_record/encryption/key.rb +28 -0
  120. data/lib/active_record/encryption/key_generator.rb +42 -0
  121. data/lib/active_record/encryption/key_provider.rb +46 -0
  122. data/lib/active_record/encryption/message.rb +33 -0
  123. data/lib/active_record/encryption/message_serializer.rb +90 -0
  124. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  125. data/lib/active_record/encryption/properties.rb +76 -0
  126. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  127. data/lib/active_record/encryption/scheme.rb +99 -0
  128. data/lib/active_record/encryption.rb +55 -0
  129. data/lib/active_record/enum.rb +49 -42
  130. data/lib/active_record/errors.rb +67 -4
  131. data/lib/active_record/explain_registry.rb +11 -6
  132. data/lib/active_record/fixture_set/file.rb +15 -1
  133. data/lib/active_record/fixture_set/table_row.rb +41 -6
  134. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  135. data/lib/active_record/fixtures.rb +17 -20
  136. data/lib/active_record/future_result.rb +139 -0
  137. data/lib/active_record/gem_version.rb +4 -4
  138. data/lib/active_record/inheritance.rb +55 -17
  139. data/lib/active_record/insert_all.rb +80 -14
  140. data/lib/active_record/integration.rb +4 -3
  141. data/lib/active_record/internal_metadata.rb +1 -5
  142. data/lib/active_record/legacy_yaml_adapter.rb +2 -39
  143. data/lib/active_record/locking/optimistic.rb +10 -9
  144. data/lib/active_record/locking/pessimistic.rb +9 -3
  145. data/lib/active_record/log_subscriber.rb +14 -3
  146. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  147. data/lib/active_record/middleware/database_selector.rb +8 -3
  148. data/lib/active_record/middleware/shard_selector.rb +60 -0
  149. data/lib/active_record/migration/command_recorder.rb +4 -4
  150. data/lib/active_record/migration/compatibility.rb +89 -10
  151. data/lib/active_record/migration/join_table.rb +1 -1
  152. data/lib/active_record/migration.rb +110 -80
  153. data/lib/active_record/model_schema.rb +45 -58
  154. data/lib/active_record/nested_attributes.rb +13 -12
  155. data/lib/active_record/no_touching.rb +3 -3
  156. data/lib/active_record/null_relation.rb +2 -6
  157. data/lib/active_record/persistence.rb +219 -52
  158. data/lib/active_record/query_cache.rb +2 -2
  159. data/lib/active_record/query_logs.rb +138 -0
  160. data/lib/active_record/querying.rb +15 -5
  161. data/lib/active_record/railtie.rb +127 -17
  162. data/lib/active_record/railties/controller_runtime.rb +1 -1
  163. data/lib/active_record/railties/databases.rake +66 -129
  164. data/lib/active_record/readonly_attributes.rb +11 -0
  165. data/lib/active_record/reflection.rb +67 -50
  166. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  167. data/lib/active_record/relation/batches.rb +3 -3
  168. data/lib/active_record/relation/calculations.rb +40 -36
  169. data/lib/active_record/relation/delegation.rb +6 -6
  170. data/lib/active_record/relation/finder_methods.rb +31 -35
  171. data/lib/active_record/relation/merger.rb +20 -13
  172. data/lib/active_record/relation/predicate_builder.rb +1 -6
  173. data/lib/active_record/relation/query_attribute.rb +5 -11
  174. data/lib/active_record/relation/query_methods.rb +235 -63
  175. data/lib/active_record/relation/record_fetch_warning.rb +7 -9
  176. data/lib/active_record/relation/spawn_methods.rb +2 -2
  177. data/lib/active_record/relation/where_clause.rb +10 -19
  178. data/lib/active_record/relation.rb +169 -84
  179. data/lib/active_record/result.rb +17 -7
  180. data/lib/active_record/runtime_registry.rb +9 -13
  181. data/lib/active_record/sanitization.rb +11 -7
  182. data/lib/active_record/schema_dumper.rb +10 -3
  183. data/lib/active_record/schema_migration.rb +4 -4
  184. data/lib/active_record/scoping/default.rb +61 -12
  185. data/lib/active_record/scoping/named.rb +3 -11
  186. data/lib/active_record/scoping.rb +64 -34
  187. data/lib/active_record/serialization.rb +1 -1
  188. data/lib/active_record/signed_id.rb +1 -1
  189. data/lib/active_record/store.rb +1 -6
  190. data/lib/active_record/suppressor.rb +11 -15
  191. data/lib/active_record/tasks/database_tasks.rb +116 -58
  192. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  193. data/lib/active_record/tasks/postgresql_database_tasks.rb +19 -12
  194. data/lib/active_record/test_databases.rb +1 -1
  195. data/lib/active_record/test_fixtures.rb +9 -13
  196. data/lib/active_record/timestamp.rb +3 -4
  197. data/lib/active_record/transactions.rb +9 -14
  198. data/lib/active_record/translation.rb +2 -2
  199. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  200. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  201. data/lib/active_record/type/internal/timezone.rb +2 -2
  202. data/lib/active_record/type/serialized.rb +1 -1
  203. data/lib/active_record/type/type_map.rb +17 -20
  204. data/lib/active_record/type.rb +1 -2
  205. data/lib/active_record/validations/associated.rb +1 -1
  206. data/lib/active_record/validations/uniqueness.rb +1 -1
  207. data/lib/active_record.rb +204 -28
  208. data/lib/arel/attributes/attribute.rb +0 -8
  209. data/lib/arel/crud.rb +28 -22
  210. data/lib/arel/delete_manager.rb +18 -4
  211. data/lib/arel/filter_predications.rb +9 -0
  212. data/lib/arel/insert_manager.rb +2 -3
  213. data/lib/arel/nodes/casted.rb +1 -1
  214. data/lib/arel/nodes/delete_statement.rb +12 -13
  215. data/lib/arel/nodes/filter.rb +10 -0
  216. data/lib/arel/nodes/function.rb +1 -0
  217. data/lib/arel/nodes/insert_statement.rb +2 -2
  218. data/lib/arel/nodes/select_core.rb +2 -2
  219. data/lib/arel/nodes/select_statement.rb +2 -2
  220. data/lib/arel/nodes/update_statement.rb +8 -3
  221. data/lib/arel/nodes.rb +1 -0
  222. data/lib/arel/predications.rb +11 -3
  223. data/lib/arel/select_manager.rb +10 -4
  224. data/lib/arel/table.rb +0 -1
  225. data/lib/arel/tree_manager.rb +0 -12
  226. data/lib/arel/update_manager.rb +18 -4
  227. data/lib/arel/visitors/dot.rb +80 -90
  228. data/lib/arel/visitors/mysql.rb +8 -2
  229. data/lib/arel/visitors/postgresql.rb +0 -10
  230. data/lib/arel/visitors/to_sql.rb +58 -2
  231. data/lib/arel.rb +2 -1
  232. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  233. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  234. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  235. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  236. data/lib/rails/generators/active_record/multi_db/multi_db_generator.rb +16 -0
  237. data/lib/rails/generators/active_record/multi_db/templates/multi_db.rb.tt +44 -0
  238. metadata +58 -14
@@ -37,7 +37,11 @@ module ActiveRecord
37
37
 
38
38
  return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
39
39
 
40
- name = "#{payload[:name]} (#{event.duration.round(1)}ms)"
40
+ name = if payload[:async]
41
+ "ASYNC #{payload[:name]} (#{payload[:lock_wait].round(1)}ms) (db time #{event.duration.round(1)}ms)"
42
+ else
43
+ "#{payload[:name]} (#{event.duration.round(1)}ms)"
44
+ end
41
45
  name = "CACHE #{name}" if payload[:cached]
42
46
  sql = payload[:sql]
43
47
  binds = nil
@@ -47,7 +51,10 @@ module ActiveRecord
47
51
 
48
52
  binds = []
49
53
  payload[:binds].each_with_index do |attr, i|
50
- binds << render_bind(attr, casted_params[i])
54
+ attribute_name = attr.respond_to?(:name) ? attr.name : attr[i].name
55
+ filtered_params = filter(attribute_name, casted_params[i])
56
+
57
+ binds << render_bind(attr, filtered_params)
51
58
  end
52
59
  binds = binds.inspect
53
60
  binds.prepend(" ")
@@ -115,7 +122,7 @@ module ActiveRecord
115
122
  def debug(progname = nil, &block)
116
123
  return unless super
117
124
 
118
- if ActiveRecord::Base.verbose_query_logs
125
+ if ActiveRecord.verbose_query_logs
119
126
  log_query_source
120
127
  end
121
128
  end
@@ -131,6 +138,10 @@ module ActiveRecord
131
138
  def extract_query_source_location(locations)
132
139
  backtrace_cleaner.clean(locations.lazy).first
133
140
  end
141
+
142
+ def filter(name, value)
143
+ ActiveRecord::Base.inspection_filter.filter_param(name, value)
144
+ end
134
145
  end
135
146
  end
136
147
 
@@ -50,23 +50,19 @@ module ActiveRecord
50
50
 
51
51
  private
52
52
  def read_from_primary(&blk)
53
- ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do
54
- instrumenter.instrument("database_selector.active_record.read_from_primary") do
55
- yield
56
- end
53
+ ActiveRecord::Base.connected_to(role: ActiveRecord.writing_role, prevent_writes: true) do
54
+ instrumenter.instrument("database_selector.active_record.read_from_primary", &blk)
57
55
  end
58
56
  end
59
57
 
60
58
  def read_from_replica(&blk)
61
- ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role, prevent_writes: true) do
62
- instrumenter.instrument("database_selector.active_record.read_from_replica") do
63
- yield
64
- end
59
+ ActiveRecord::Base.connected_to(role: ActiveRecord.reading_role, prevent_writes: true) do
60
+ instrumenter.instrument("database_selector.active_record.read_from_replica", &blk)
65
61
  end
66
62
  end
67
63
 
68
- def write_to_primary(&blk)
69
- ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: false) do
64
+ def write_to_primary
65
+ ActiveRecord::Base.connected_to(role: ActiveRecord.writing_role, prevent_writes: false) do
70
66
  instrumenter.instrument("database_selector.active_record.wrote_to_primary") do
71
67
  yield
72
68
  ensure
@@ -22,9 +22,14 @@ module ActiveRecord
22
22
  # To use the DatabaseSelector in your application with default settings add
23
23
  # the following options to your environment config:
24
24
  #
25
- # config.active_record.database_selector = { delay: 2.seconds }
26
- # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
27
- # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
25
+ # # This require is only necessary when using `rails new app --minimal`
26
+ # require "active_support/core_ext/integer/time"
27
+ #
28
+ # class Application < Rails::Application
29
+ # config.active_record.database_selector = { delay: 2.seconds }
30
+ # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
31
+ # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
32
+ # end
28
33
  #
29
34
  # New applications will include these lines commented out in the production.rb.
30
35
  #
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Middleware
5
+ # The ShardSelector Middleware provides a framework for automatically
6
+ # swapping shards. Rails provides a basic framework to determine which
7
+ # shard to switch to and allows for applications to write custom strategies
8
+ # for swapping if needed.
9
+ #
10
+ # The ShardSelector takes a set of options (currently only `lock` is supported)
11
+ # that can be used by the middleware to alter behavior. `lock` is
12
+ # true by default and will prohibit the request from switching shards once
13
+ # inside the block. If `lock` is false, then shard swapping will be allowed.
14
+ # For tenant based sharding, `lock` should always be true to prevent application
15
+ # code from mistakenly switching between tenants.
16
+ #
17
+ # Options can be set in the config:
18
+ #
19
+ # config.active_record.shard_selector = { lock: true }
20
+ #
21
+ # Applications must also provide the code for the resolver as it depends on application
22
+ # specific models. An example resolver would look like this:
23
+ #
24
+ # config.active_record.shard_resolver = ->(request) {
25
+ # subdomain = request.subdomain
26
+ # tenant = Tenant.find_by_subdomain!(subdomain)
27
+ # tenant.shard
28
+ # }
29
+ class ShardSelector
30
+ def initialize(app, resolver, options = {})
31
+ @app = app
32
+ @resolver = resolver
33
+ @options = options
34
+ end
35
+
36
+ attr_reader :resolver, :options
37
+
38
+ def call(env)
39
+ request = ActionDispatch::Request.new(env)
40
+
41
+ shard = selected_shard(request)
42
+
43
+ set_shard(shard) do
44
+ @app.call(env)
45
+ end
46
+ end
47
+
48
+ private
49
+ def selected_shard(request)
50
+ resolver.call(request)
51
+ end
52
+
53
+ def set_shard(shard, &block)
54
+ ActiveRecord::Base.connected_to(shard: shard.to_sym) do
55
+ ActiveRecord::Base.prohibit_shard_swapping(options.fetch(:lock, true), &block)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -112,7 +112,7 @@ module ActiveRecord
112
112
  record(:"#{method}", args, &block) # record(:create_table, args, &block)
113
113
  end # end
114
114
  EOV
115
- ruby2_keywords(method) if respond_to?(:ruby2_keywords, true)
115
+ ruby2_keywords(method)
116
116
  end
117
117
  alias :add_belongs_to :add_reference
118
118
  alias :remove_belongs_to :remove_reference
@@ -154,9 +154,9 @@ module ActiveRecord
154
154
 
155
155
  include StraightReversions
156
156
 
157
- def invert_transaction(args)
157
+ def invert_transaction(args, &block)
158
158
  sub_recorder = CommandRecorder.new(delegate)
159
- sub_recorder.revert { yield }
159
+ sub_recorder.revert(&block)
160
160
 
161
161
  invertions_proc = proc {
162
162
  sub_recorder.replay(self)
@@ -286,7 +286,7 @@ module ActiveRecord
286
286
  super
287
287
  end
288
288
  end
289
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
289
+ ruby2_keywords(:method_missing)
290
290
  end
291
291
  end
292
292
  end
@@ -13,7 +13,77 @@ module ActiveRecord
13
13
  const_get(name)
14
14
  end
15
15
 
16
- V6_1 = Current
16
+ # This file exists to ensure that old migrations run the same way they did before a Rails upgrade.
17
+ # e.g. if you write a migration on Rails 6.1, then upgrade to Rails 7, the migration should do the same thing to your
18
+ # database as it did when you were running Rails 6.1
19
+ #
20
+ # "Current" is an alias for `ActiveRecord::Migration`, it represents the current Rails version.
21
+ # New migration functionality that will never be backward compatible should be added directly to `ActiveRecord::Migration`.
22
+ #
23
+ # There are classes for each prior Rails version. Each class descends from the *next* Rails version, so:
24
+ # 6.1 < 7.0
25
+ # 5.2 < 6.0 < 6.1 < 7.0
26
+ #
27
+ # If you are introducing new migration functionality that should only apply from Rails 7 onward, then you should
28
+ # find the class that immediately precedes it (6.1), and override the relevant migration methods to undo your changes.
29
+ #
30
+ # For example, Rails 6 added a default value for the `precision` option on datetime columns. So in this file, the `V5_2`
31
+ # class sets the value of `precision` to `nil` if it's not explicitly provided. This way, the default value will not apply
32
+ # for migrations written for 5.2, but will for migrations written for 6.0.
33
+ V7_0 = Current
34
+
35
+ class V6_1 < V7_0
36
+ class PostgreSQLCompat
37
+ def self.compatible_timestamp_type(type, connection)
38
+ if connection.adapter_name == "PostgreSQL"
39
+ # For Rails <= 6.1, :datetime was aliased to :timestamp
40
+ # See: https://github.com/rails/rails/blob/v6.1.3.2/activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb#L108
41
+ # From Rails 7 onwards, you can define what :datetime resolves to (the default is still :timestamp)
42
+ # See `ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type`
43
+ type.to_sym == :datetime ? :timestamp : type
44
+ else
45
+ type
46
+ end
47
+ end
48
+ end
49
+
50
+ def add_column(table_name, column_name, type, **options)
51
+ if type == :datetime
52
+ options[:precision] ||= nil
53
+ end
54
+
55
+ type = PostgreSQLCompat.compatible_timestamp_type(type, connection)
56
+ super
57
+ end
58
+
59
+ def create_table(table_name, **options)
60
+ if block_given?
61
+ super { |t| yield compatible_table_definition(t) }
62
+ else
63
+ super
64
+ end
65
+ end
66
+
67
+ module TableDefinition
68
+ def new_column_definition(name, type, **options)
69
+ type = PostgreSQLCompat.compatible_timestamp_type(type, @conn)
70
+ super
71
+ end
72
+
73
+ def column(name, type, index: nil, **options)
74
+ options[:precision] ||= nil
75
+ super
76
+ end
77
+ end
78
+
79
+ private
80
+ def compatible_table_definition(t)
81
+ class << t
82
+ prepend TableDefinition
83
+ end
84
+ t
85
+ end
86
+ end
17
87
 
18
88
  class V6_0 < V6_1
19
89
  class ReferenceDefinition < ConnectionAdapters::ReferenceDefinition
@@ -24,10 +94,16 @@ module ActiveRecord
24
94
 
25
95
  module TableDefinition
26
96
  def references(*args, **options)
27
- options[:_uses_legacy_reference_index_name] = true
28
- super
97
+ args.each do |ref_name|
98
+ ReferenceDefinition.new(ref_name, **options).add_to(self)
99
+ end
29
100
  end
30
101
  alias :belongs_to :references
102
+
103
+ def column(name, type, index: nil, **options)
104
+ options[:precision] ||= nil
105
+ super
106
+ end
31
107
  end
32
108
 
33
109
  def create_table(table_name, **options)
@@ -55,12 +131,8 @@ module ActiveRecord
55
131
  end
56
132
 
57
133
  def add_reference(table_name, ref_name, **options)
58
- if connection.adapter_name == "SQLite"
59
- options[:type] = :integer
60
- end
61
-
62
- options[:_uses_legacy_reference_index_name] = true
63
- super
134
+ ReferenceDefinition.new(ref_name, **options)
135
+ .add_to(connection.update_table_definition(table_name, self))
64
136
  end
65
137
  alias :add_belongs_to :add_reference
66
138
 
@@ -79,6 +151,11 @@ module ActiveRecord
79
151
  options[:precision] ||= nil
80
152
  super
81
153
  end
154
+
155
+ def column(name, type, index: nil, **options)
156
+ options[:precision] ||= nil
157
+ super
158
+ end
82
159
  end
83
160
 
84
161
  module CommandRecorder
@@ -129,7 +206,7 @@ module ActiveRecord
129
206
  class << t
130
207
  prepend TableDefinition
131
208
  end
132
- super
209
+ t
133
210
  end
134
211
 
135
212
  def command_recorder
@@ -207,6 +284,8 @@ module ActiveRecord
207
284
  if type == :primary_key
208
285
  type = :integer
209
286
  options[:primary_key] = true
287
+ elsif type == :datetime
288
+ options[:precision] ||= nil
210
289
  end
211
290
  super
212
291
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ActiveRecord
4
4
  class Migration
5
- module JoinTable #:nodoc:
5
+ module JoinTable # :nodoc:
6
6
  private
7
7
  def find_join_table_name(table_1, table_2, options = {})
8
8
  options.delete(:table_name) || join_table_name(table_1, table_2)