activerecord 6.1.6 → 7.0.0.alpha1

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 (218) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +728 -1279
  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 +31 -9
  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 +1 -1
  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 +14 -23
  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/preloader/association.rb +161 -47
  25. data/lib/active_record/associations/preloader/batch.rb +51 -0
  26. data/lib/active_record/associations/preloader/branch.rb +147 -0
  27. data/lib/active_record/associations/preloader/through_association.rb +37 -11
  28. data/lib/active_record/associations/preloader.rb +46 -110
  29. data/lib/active_record/associations/singular_association.rb +8 -2
  30. data/lib/active_record/associations/through_association.rb +1 -1
  31. data/lib/active_record/associations.rb +76 -81
  32. data/lib/active_record/asynchronous_queries_tracker.rb +57 -0
  33. data/lib/active_record/attribute_assignment.rb +1 -1
  34. data/lib/active_record/attribute_methods/before_type_cast.rb +7 -2
  35. data/lib/active_record/attribute_methods/dirty.rb +41 -16
  36. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  37. data/lib/active_record/attribute_methods/query.rb +2 -2
  38. data/lib/active_record/attribute_methods/read.rb +7 -5
  39. data/lib/active_record/attribute_methods/serialization.rb +66 -12
  40. data/lib/active_record/attribute_methods/time_zone_conversion.rb +4 -3
  41. data/lib/active_record/attribute_methods/write.rb +7 -10
  42. data/lib/active_record/attribute_methods.rb +6 -9
  43. data/lib/active_record/attributes.rb +24 -35
  44. data/lib/active_record/autosave_association.rb +3 -18
  45. data/lib/active_record/base.rb +19 -1
  46. data/lib/active_record/callbacks.rb +2 -2
  47. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +312 -0
  48. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +209 -0
  49. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +76 -0
  50. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -558
  51. data/lib/active_record/connection_adapters/abstract/database_statements.rb +45 -21
  52. data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -12
  53. data/lib/active_record/connection_adapters/abstract/quoting.rb +11 -4
  54. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +4 -17
  55. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +30 -13
  56. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +60 -16
  57. data/lib/active_record/connection_adapters/abstract/transaction.rb +3 -3
  58. data/lib/active_record/connection_adapters/abstract_adapter.rb +112 -66
  59. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +96 -81
  60. data/lib/active_record/connection_adapters/mysql/database_statements.rb +33 -23
  61. data/lib/active_record/connection_adapters/mysql/quoting.rb +16 -1
  62. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +1 -1
  63. data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -6
  64. data/lib/active_record/connection_adapters/pool_config.rb +1 -3
  65. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +19 -14
  66. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +8 -0
  67. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +5 -0
  68. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +53 -14
  69. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  70. data/lib/active_record/connection_adapters/postgresql/oid/timestamp.rb +15 -0
  71. data/lib/active_record/connection_adapters/postgresql/oid/timestamp_with_time_zone.rb +28 -0
  72. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +18 -6
  73. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  74. data/lib/active_record/connection_adapters/postgresql/quoting.rb +6 -6
  75. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +32 -0
  76. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +5 -1
  77. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -12
  78. data/lib/active_record/connection_adapters/postgresql_adapter.rb +157 -100
  79. data/lib/active_record/connection_adapters/schema_cache.rb +36 -37
  80. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +23 -19
  81. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +4 -2
  82. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -30
  83. data/lib/active_record/connection_adapters.rb +6 -5
  84. data/lib/active_record/connection_handling.rb +20 -38
  85. data/lib/active_record/core.rb +111 -110
  86. data/lib/active_record/database_configurations/connection_url_resolver.rb +0 -1
  87. data/lib/active_record/database_configurations/database_config.rb +12 -0
  88. data/lib/active_record/database_configurations/hash_config.rb +27 -1
  89. data/lib/active_record/database_configurations/url_config.rb +2 -2
  90. data/lib/active_record/database_configurations.rb +17 -9
  91. data/lib/active_record/delegated_type.rb +33 -11
  92. data/lib/active_record/destroy_association_async_job.rb +1 -1
  93. data/lib/active_record/disable_joins_association_relation.rb +39 -0
  94. data/lib/active_record/dynamic_matchers.rb +1 -1
  95. data/lib/active_record/encryption/cipher/aes256_gcm.rb +98 -0
  96. data/lib/active_record/encryption/cipher.rb +53 -0
  97. data/lib/active_record/encryption/config.rb +44 -0
  98. data/lib/active_record/encryption/configurable.rb +61 -0
  99. data/lib/active_record/encryption/context.rb +35 -0
  100. data/lib/active_record/encryption/contexts.rb +72 -0
  101. data/lib/active_record/encryption/derived_secret_key_provider.rb +12 -0
  102. data/lib/active_record/encryption/deterministic_key_provider.rb +14 -0
  103. data/lib/active_record/encryption/encryptable_record.rb +208 -0
  104. data/lib/active_record/encryption/encrypted_attribute_type.rb +140 -0
  105. data/lib/active_record/encryption/encrypted_fixtures.rb +38 -0
  106. data/lib/active_record/encryption/encrypting_only_encryptor.rb +12 -0
  107. data/lib/active_record/encryption/encryptor.rb +155 -0
  108. data/lib/active_record/encryption/envelope_encryption_key_provider.rb +55 -0
  109. data/lib/active_record/encryption/errors.rb +15 -0
  110. data/lib/active_record/encryption/extended_deterministic_queries.rb +160 -0
  111. data/lib/active_record/encryption/extended_deterministic_uniqueness_validator.rb +29 -0
  112. data/lib/active_record/encryption/key.rb +28 -0
  113. data/lib/active_record/encryption/key_generator.rb +42 -0
  114. data/lib/active_record/encryption/key_provider.rb +46 -0
  115. data/lib/active_record/encryption/message.rb +33 -0
  116. data/lib/active_record/encryption/message_serializer.rb +80 -0
  117. data/lib/active_record/encryption/null_encryptor.rb +21 -0
  118. data/lib/active_record/encryption/properties.rb +76 -0
  119. data/lib/active_record/encryption/read_only_null_encryptor.rb +24 -0
  120. data/lib/active_record/encryption/scheme.rb +99 -0
  121. data/lib/active_record/encryption.rb +55 -0
  122. data/lib/active_record/enum.rb +41 -41
  123. data/lib/active_record/errors.rb +66 -3
  124. data/lib/active_record/fixture_set/file.rb +15 -1
  125. data/lib/active_record/fixture_set/table_row.rb +40 -5
  126. data/lib/active_record/fixture_set/table_rows.rb +4 -4
  127. data/lib/active_record/fixtures.rb +16 -11
  128. data/lib/active_record/future_result.rb +139 -0
  129. data/lib/active_record/gem_version.rb +4 -4
  130. data/lib/active_record/inheritance.rb +55 -17
  131. data/lib/active_record/insert_all.rb +34 -5
  132. data/lib/active_record/integration.rb +1 -1
  133. data/lib/active_record/internal_metadata.rb +1 -5
  134. data/lib/active_record/locking/optimistic.rb +10 -9
  135. data/lib/active_record/log_subscriber.rb +6 -2
  136. data/lib/active_record/middleware/database_selector/resolver.rb +6 -10
  137. data/lib/active_record/middleware/database_selector.rb +8 -3
  138. data/lib/active_record/migration/command_recorder.rb +4 -4
  139. data/lib/active_record/migration/compatibility.rb +89 -10
  140. data/lib/active_record/migration/join_table.rb +1 -1
  141. data/lib/active_record/migration.rb +109 -79
  142. data/lib/active_record/model_schema.rb +45 -31
  143. data/lib/active_record/nested_attributes.rb +3 -3
  144. data/lib/active_record/no_touching.rb +2 -2
  145. data/lib/active_record/null_relation.rb +2 -6
  146. data/lib/active_record/persistence.rb +134 -45
  147. data/lib/active_record/query_cache.rb +2 -2
  148. data/lib/active_record/query_logs.rb +203 -0
  149. data/lib/active_record/querying.rb +15 -5
  150. data/lib/active_record/railtie.rb +117 -17
  151. data/lib/active_record/railties/controller_runtime.rb +1 -1
  152. data/lib/active_record/railties/databases.rake +72 -48
  153. data/lib/active_record/readonly_attributes.rb +11 -0
  154. data/lib/active_record/reflection.rb +45 -44
  155. data/lib/active_record/relation/batches/batch_enumerator.rb +19 -5
  156. data/lib/active_record/relation/batches.rb +3 -3
  157. data/lib/active_record/relation/calculations.rb +39 -26
  158. data/lib/active_record/relation/delegation.rb +6 -6
  159. data/lib/active_record/relation/finder_methods.rb +31 -22
  160. data/lib/active_record/relation/merger.rb +20 -13
  161. data/lib/active_record/relation/predicate_builder.rb +1 -6
  162. data/lib/active_record/relation/query_attribute.rb +5 -11
  163. data/lib/active_record/relation/query_methods.rb +230 -47
  164. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  165. data/lib/active_record/relation/spawn_methods.rb +2 -2
  166. data/lib/active_record/relation/where_clause.rb +8 -4
  167. data/lib/active_record/relation.rb +166 -77
  168. data/lib/active_record/result.rb +17 -2
  169. data/lib/active_record/runtime_registry.rb +2 -4
  170. data/lib/active_record/sanitization.rb +11 -7
  171. data/lib/active_record/schema_dumper.rb +3 -3
  172. data/lib/active_record/schema_migration.rb +0 -4
  173. data/lib/active_record/scoping/default.rb +61 -12
  174. data/lib/active_record/scoping/named.rb +3 -11
  175. data/lib/active_record/scoping.rb +40 -22
  176. data/lib/active_record/serialization.rb +1 -1
  177. data/lib/active_record/signed_id.rb +1 -1
  178. data/lib/active_record/tasks/database_tasks.rb +106 -22
  179. data/lib/active_record/tasks/mysql_database_tasks.rb +1 -1
  180. data/lib/active_record/tasks/postgresql_database_tasks.rb +14 -11
  181. data/lib/active_record/test_databases.rb +1 -1
  182. data/lib/active_record/test_fixtures.rb +4 -4
  183. data/lib/active_record/timestamp.rb +3 -4
  184. data/lib/active_record/transactions.rb +9 -14
  185. data/lib/active_record/translation.rb +2 -2
  186. data/lib/active_record/type/adapter_specific_registry.rb +32 -7
  187. data/lib/active_record/type/hash_lookup_type_map.rb +34 -1
  188. data/lib/active_record/type/internal/timezone.rb +2 -2
  189. data/lib/active_record/type/serialized.rb +1 -1
  190. data/lib/active_record/type/type_map.rb +17 -20
  191. data/lib/active_record/type.rb +1 -2
  192. data/lib/active_record/validations/associated.rb +1 -1
  193. data/lib/active_record.rb +170 -2
  194. data/lib/arel/attributes/attribute.rb +0 -8
  195. data/lib/arel/crud.rb +18 -22
  196. data/lib/arel/delete_manager.rb +2 -4
  197. data/lib/arel/insert_manager.rb +2 -3
  198. data/lib/arel/nodes/casted.rb +1 -1
  199. data/lib/arel/nodes/delete_statement.rb +8 -13
  200. data/lib/arel/nodes/insert_statement.rb +2 -2
  201. data/lib/arel/nodes/select_core.rb +2 -2
  202. data/lib/arel/nodes/select_statement.rb +2 -2
  203. data/lib/arel/nodes/update_statement.rb +3 -2
  204. data/lib/arel/predications.rb +1 -1
  205. data/lib/arel/select_manager.rb +10 -4
  206. data/lib/arel/table.rb +0 -1
  207. data/lib/arel/tree_manager.rb +0 -12
  208. data/lib/arel/update_manager.rb +2 -4
  209. data/lib/arel/visitors/dot.rb +80 -90
  210. data/lib/arel/visitors/mysql.rb +6 -1
  211. data/lib/arel/visitors/postgresql.rb +0 -10
  212. data/lib/arel/visitors/to_sql.rb +43 -2
  213. data/lib/arel.rb +1 -1
  214. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +1 -1
  215. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +1 -1
  216. data/lib/rails/generators/active_record/model/templates/model.rb.tt +1 -1
  217. data/lib/rails/generators/active_record/model/templates/module.rb.tt +2 -2
  218. metadata +55 -17
@@ -5,7 +5,7 @@ require "active_support/core_ext/enumerable"
5
5
  module ActiveRecord
6
6
  class InsertAll # :nodoc:
7
7
  attr_reader :model, :connection, :inserts, :keys
8
- attr_reader :on_duplicate, :returning, :unique_by
8
+ attr_reader :on_duplicate, :returning, :unique_by, :update_sql
9
9
 
10
10
  def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
11
11
  raise ArgumentError, "Empty list of attributes passed" if inserts.blank?
@@ -13,6 +13,14 @@ module ActiveRecord
13
13
  @model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
14
14
  @on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
15
15
 
16
+ disallow_raw_sql!(returning)
17
+ disallow_raw_sql!(on_duplicate)
18
+
19
+ if Arel.arel_node?(on_duplicate)
20
+ @update_sql = on_duplicate
21
+ @on_duplicate = :update
22
+ end
23
+
16
24
  if model.scope_attributes?
17
25
  @scope_attributes = model.scope_attributes
18
26
  @keys |= @scope_attributes.keys
@@ -131,6 +139,15 @@ module ActiveRecord
131
139
  end
132
140
  end
133
141
 
142
+ def disallow_raw_sql!(value)
143
+ return if !value.is_a?(String) || Arel.arel_node?(value)
144
+
145
+ raise ArgumentError, "Dangerous query method (method whose arguments are used as raw " \
146
+ "SQL) called: #{value}. " \
147
+ "Known-safe values can be passed " \
148
+ "by wrapping them in Arel.sql()."
149
+ end
150
+
134
151
  class Builder # :nodoc:
135
152
  attr_reader :model
136
153
 
@@ -155,7 +172,13 @@ module ActiveRecord
155
172
  end
156
173
 
157
174
  def returning
158
- format_columns(insert_all.returning) if insert_all.returning
175
+ return unless insert_all.returning
176
+
177
+ if insert_all.returning.is_a?(String)
178
+ insert_all.returning
179
+ else
180
+ format_columns(insert_all.returning)
181
+ end
159
182
  end
160
183
 
161
184
  def conflict_target
@@ -173,13 +196,19 @@ module ActiveRecord
173
196
  end
174
197
 
175
198
  def touch_model_timestamps_unless(&block)
176
- model.send(:timestamp_attributes_for_update_in_model).map do |column_name|
199
+ model.timestamp_attributes_for_update_in_model.filter_map do |column_name|
177
200
  if touch_timestamp_attribute?(column_name)
178
- "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE CURRENT_TIMESTAMP END),"
201
+ "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE #{connection.high_precision_current_timestamp} END),"
179
202
  end
180
- end.compact.join
203
+ end.join
181
204
  end
182
205
 
206
+ def raw_update_sql
207
+ insert_all.update_sql
208
+ end
209
+
210
+ alias raw_update_sql? raw_update_sql
211
+
183
212
  private
184
213
  attr_reader :connection, :insert_all
185
214
 
@@ -177,7 +177,7 @@ module ActiveRecord
177
177
  def can_use_fast_cache_version?(timestamp)
178
178
  timestamp.is_a?(String) &&
179
179
  cache_timestamp_format == :usec &&
180
- default_timezone == :utc &&
180
+ ActiveRecord.default_timezone == :utc &&
181
181
  !updated_at_came_from_user?
182
182
  end
183
183
 
@@ -17,10 +17,6 @@ module ActiveRecord
17
17
  ActiveRecord::Base.connection.use_metadata_table?
18
18
  end
19
19
 
20
- def _internal?
21
- true
22
- end
23
-
24
20
  def primary_key
25
21
  "key"
26
22
  end
@@ -38,7 +34,7 @@ module ActiveRecord
38
34
  def [](key)
39
35
  return unless enabled?
40
36
 
41
- where(key: key).pluck(:value).first
37
+ where(key: key).pick(:value)
42
38
  end
43
39
 
44
40
  # Creates an internal metadata table with columns +key+ and +value+
@@ -56,11 +56,11 @@ module ActiveRecord
56
56
  class_attribute :lock_optimistically, instance_writer: false, default: true
57
57
  end
58
58
 
59
- def locking_enabled? #:nodoc:
59
+ def locking_enabled? # :nodoc:
60
60
  self.class.locking_enabled?
61
61
  end
62
62
 
63
- def increment!(*, **) #:nodoc:
63
+ def increment!(*, **) # :nodoc:
64
64
  super.tap do
65
65
  if locking_enabled?
66
66
  self[self.class.locking_column] += 1
@@ -90,7 +90,9 @@ module ActiveRecord
90
90
  begin
91
91
  locking_column = self.class.locking_column
92
92
  lock_attribute_was = @attributes[locking_column]
93
- lock_value_for_database = _lock_value_for_database(locking_column)
93
+
94
+ update_constraints = _primary_key_constraints_hash
95
+ update_constraints[locking_column] = _lock_value_for_database(locking_column)
94
96
 
95
97
  attribute_names = attribute_names.dup if attribute_names.frozen?
96
98
  attribute_names << locking_column
@@ -99,8 +101,7 @@ module ActiveRecord
99
101
 
100
102
  affected_rows = self.class._update_record(
101
103
  attributes_with_values(attribute_names),
102
- @primary_key => id_in_database,
103
- locking_column => lock_value_for_database
104
+ update_constraints
104
105
  )
105
106
 
106
107
  if affected_rows != 1
@@ -121,10 +122,10 @@ module ActiveRecord
121
122
 
122
123
  locking_column = self.class.locking_column
123
124
 
124
- affected_rows = self.class._delete_record(
125
- @primary_key => id_in_database,
126
- locking_column => _lock_value_for_database(locking_column)
127
- )
125
+ delete_constraints = _primary_key_constraints_hash
126
+ delete_constraints[locking_column] = _lock_value_for_database(locking_column)
127
+
128
+ affected_rows = self.class._delete_record(delete_constraints)
128
129
 
129
130
  if affected_rows != 1
130
131
  raise ActiveRecord::StaleObjectError.new(self, "destroy")
@@ -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
@@ -115,7 +119,7 @@ module ActiveRecord
115
119
  def debug(progname = nil, &block)
116
120
  return unless super
117
121
 
118
- if ActiveRecord::Base.verbose_query_logs
122
+ if ActiveRecord.verbose_query_logs
119
123
  log_query_source
120
124
  end
121
125
  end
@@ -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
  #
@@ -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)