activerecord 6.0.3.4 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (244) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +799 -713
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_record.rb +7 -14
  6. data/lib/active_record/aggregations.rb +1 -1
  7. data/lib/active_record/association_relation.rb +22 -14
  8. data/lib/active_record/associations.rb +114 -11
  9. data/lib/active_record/associations/alias_tracker.rb +19 -15
  10. data/lib/active_record/associations/association.rb +44 -28
  11. data/lib/active_record/associations/association_scope.rb +17 -15
  12. data/lib/active_record/associations/belongs_to_association.rb +15 -5
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +1 -1
  14. data/lib/active_record/associations/builder/association.rb +9 -3
  15. data/lib/active_record/associations/builder/belongs_to.rb +10 -7
  16. data/lib/active_record/associations/builder/collection_association.rb +5 -4
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +0 -1
  18. data/lib/active_record/associations/builder/has_many.rb +6 -2
  19. data/lib/active_record/associations/builder/has_one.rb +11 -14
  20. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  21. data/lib/active_record/associations/collection_association.rb +19 -6
  22. data/lib/active_record/associations/collection_proxy.rb +13 -5
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +24 -2
  25. data/lib/active_record/associations/has_many_through_association.rb +10 -4
  26. data/lib/active_record/associations/has_one_association.rb +15 -1
  27. data/lib/active_record/associations/join_dependency.rb +72 -50
  28. data/lib/active_record/associations/join_dependency/join_association.rb +36 -14
  29. data/lib/active_record/associations/join_dependency/join_part.rb +3 -3
  30. data/lib/active_record/associations/preloader.rb +11 -5
  31. data/lib/active_record/associations/preloader/association.rb +51 -25
  32. data/lib/active_record/associations/preloader/through_association.rb +2 -2
  33. data/lib/active_record/associations/singular_association.rb +1 -1
  34. data/lib/active_record/associations/through_association.rb +1 -1
  35. data/lib/active_record/attribute_assignment.rb +10 -8
  36. data/lib/active_record/attribute_methods.rb +64 -54
  37. data/lib/active_record/attribute_methods/before_type_cast.rb +13 -9
  38. data/lib/active_record/attribute_methods/dirty.rb +1 -11
  39. data/lib/active_record/attribute_methods/primary_key.rb +6 -2
  40. data/lib/active_record/attribute_methods/query.rb +3 -6
  41. data/lib/active_record/attribute_methods/read.rb +8 -11
  42. data/lib/active_record/attribute_methods/serialization.rb +11 -5
  43. data/lib/active_record/attribute_methods/time_zone_conversion.rb +12 -13
  44. data/lib/active_record/attribute_methods/write.rb +12 -20
  45. data/lib/active_record/attributes.rb +32 -7
  46. data/lib/active_record/autosave_association.rb +57 -40
  47. data/lib/active_record/base.rb +2 -14
  48. data/lib/active_record/callbacks.rb +152 -22
  49. data/lib/active_record/coders/yaml_column.rb +1 -1
  50. data/lib/active_record/connection_adapters.rb +50 -0
  51. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +191 -134
  52. data/lib/active_record/connection_adapters/abstract/database_limits.rb +2 -44
  53. data/lib/active_record/connection_adapters/abstract/database_statements.rb +65 -22
  54. data/lib/active_record/connection_adapters/abstract/query_cache.rb +2 -7
  55. data/lib/active_record/connection_adapters/abstract/quoting.rb +34 -34
  56. data/lib/active_record/connection_adapters/abstract/savepoints.rb +3 -3
  57. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +153 -116
  58. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +112 -27
  59. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +3 -3
  60. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +224 -85
  61. data/lib/active_record/connection_adapters/abstract/transaction.rb +80 -32
  62. data/lib/active_record/connection_adapters/abstract_adapter.rb +54 -71
  63. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +129 -88
  64. data/lib/active_record/connection_adapters/column.rb +15 -1
  65. data/lib/active_record/connection_adapters/deduplicable.rb +29 -0
  66. data/lib/active_record/connection_adapters/legacy_pool_manager.rb +31 -0
  67. data/lib/active_record/connection_adapters/mysql/database_statements.rb +23 -25
  68. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +1 -1
  69. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -1
  70. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +32 -6
  71. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +8 -0
  72. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +1 -1
  73. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +11 -7
  74. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +10 -1
  75. data/lib/active_record/connection_adapters/mysql2_adapter.rb +31 -12
  76. data/lib/active_record/connection_adapters/pool_config.rb +63 -0
  77. data/lib/active_record/connection_adapters/pool_manager.rb +43 -0
  78. data/lib/active_record/connection_adapters/postgresql/column.rb +24 -1
  79. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +13 -54
  80. data/lib/active_record/connection_adapters/postgresql/oid.rb +2 -0
  81. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +3 -5
  82. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +2 -2
  83. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +10 -2
  84. data/lib/active_record/connection_adapters/postgresql/oid/interval.rb +49 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -2
  86. data/lib/active_record/connection_adapters/postgresql/oid/macaddr.rb +25 -0
  87. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +24 -5
  89. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +11 -1
  90. data/lib/active_record/connection_adapters/postgresql/quoting.rb +4 -4
  91. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +1 -1
  92. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +5 -1
  93. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +61 -29
  94. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +8 -0
  95. data/lib/active_record/connection_adapters/postgresql_adapter.rb +72 -55
  96. data/lib/active_record/connection_adapters/schema_cache.rb +98 -15
  97. data/lib/active_record/connection_adapters/sql_type_metadata.rb +10 -0
  98. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +31 -6
  99. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +1 -1
  100. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +5 -1
  101. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +37 -4
  102. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +49 -50
  103. data/lib/active_record/connection_handling.rb +210 -71
  104. data/lib/active_record/core.rb +229 -63
  105. data/lib/active_record/database_configurations.rb +124 -85
  106. data/lib/active_record/database_configurations/connection_url_resolver.rb +98 -0
  107. data/lib/active_record/database_configurations/database_config.rb +52 -9
  108. data/lib/active_record/database_configurations/hash_config.rb +54 -8
  109. data/lib/active_record/database_configurations/url_config.rb +15 -40
  110. data/lib/active_record/delegated_type.rb +209 -0
  111. data/lib/active_record/destroy_association_async_job.rb +36 -0
  112. data/lib/active_record/enum.rb +40 -16
  113. data/lib/active_record/errors.rb +47 -12
  114. data/lib/active_record/explain.rb +9 -4
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +10 -17
  117. data/lib/active_record/fixture_set/model_metadata.rb +1 -2
  118. data/lib/active_record/fixture_set/render_context.rb +1 -1
  119. data/lib/active_record/fixture_set/table_row.rb +2 -2
  120. data/lib/active_record/fixtures.rb +54 -8
  121. data/lib/active_record/gem_version.rb +3 -3
  122. data/lib/active_record/inheritance.rb +40 -18
  123. data/lib/active_record/insert_all.rb +35 -6
  124. data/lib/active_record/integration.rb +3 -5
  125. data/lib/active_record/internal_metadata.rb +16 -7
  126. data/lib/active_record/legacy_yaml_adapter.rb +7 -3
  127. data/lib/active_record/locking/optimistic.rb +22 -16
  128. data/lib/active_record/locking/pessimistic.rb +6 -2
  129. data/lib/active_record/log_subscriber.rb +26 -8
  130. data/lib/active_record/middleware/database_selector.rb +4 -1
  131. data/lib/active_record/middleware/database_selector/resolver.rb +5 -0
  132. data/lib/active_record/middleware/database_selector/resolver/session.rb +3 -0
  133. data/lib/active_record/migration.rb +113 -83
  134. data/lib/active_record/migration/command_recorder.rb +47 -27
  135. data/lib/active_record/migration/compatibility.rb +67 -17
  136. data/lib/active_record/model_schema.rb +117 -13
  137. data/lib/active_record/nested_attributes.rb +2 -3
  138. data/lib/active_record/no_touching.rb +1 -1
  139. data/lib/active_record/persistence.rb +50 -45
  140. data/lib/active_record/query_cache.rb +15 -5
  141. data/lib/active_record/querying.rb +11 -6
  142. data/lib/active_record/railtie.rb +64 -44
  143. data/lib/active_record/railties/databases.rake +266 -95
  144. data/lib/active_record/readonly_attributes.rb +4 -0
  145. data/lib/active_record/reflection.rb +71 -57
  146. data/lib/active_record/relation.rb +96 -67
  147. data/lib/active_record/relation/batches.rb +38 -31
  148. data/lib/active_record/relation/batches/batch_enumerator.rb +25 -9
  149. data/lib/active_record/relation/calculations.rb +101 -44
  150. data/lib/active_record/relation/delegation.rb +2 -1
  151. data/lib/active_record/relation/finder_methods.rb +45 -15
  152. data/lib/active_record/relation/from_clause.rb +1 -1
  153. data/lib/active_record/relation/merger.rb +27 -25
  154. data/lib/active_record/relation/predicate_builder.rb +57 -33
  155. data/lib/active_record/relation/predicate_builder/array_handler.rb +8 -9
  156. data/lib/active_record/relation/predicate_builder/association_query_value.rb +4 -5
  157. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +3 -3
  158. data/lib/active_record/relation/predicate_builder/relation_handler.rb +1 -1
  159. data/lib/active_record/relation/query_methods.rb +330 -195
  160. data/lib/active_record/relation/record_fetch_warning.rb +3 -3
  161. data/lib/active_record/relation/spawn_methods.rb +8 -7
  162. data/lib/active_record/relation/where_clause.rb +104 -57
  163. data/lib/active_record/result.rb +41 -33
  164. data/lib/active_record/runtime_registry.rb +2 -2
  165. data/lib/active_record/sanitization.rb +6 -17
  166. data/lib/active_record/schema_dumper.rb +34 -4
  167. data/lib/active_record/schema_migration.rb +2 -8
  168. data/lib/active_record/scoping/named.rb +6 -17
  169. data/lib/active_record/secure_token.rb +16 -8
  170. data/lib/active_record/serialization.rb +5 -3
  171. data/lib/active_record/signed_id.rb +116 -0
  172. data/lib/active_record/statement_cache.rb +20 -4
  173. data/lib/active_record/store.rb +2 -2
  174. data/lib/active_record/suppressor.rb +2 -2
  175. data/lib/active_record/table_metadata.rb +39 -51
  176. data/lib/active_record/tasks/database_tasks.rb +139 -113
  177. data/lib/active_record/tasks/mysql_database_tasks.rb +34 -35
  178. data/lib/active_record/tasks/postgresql_database_tasks.rb +24 -26
  179. data/lib/active_record/tasks/sqlite_database_tasks.rb +13 -9
  180. data/lib/active_record/test_databases.rb +5 -4
  181. data/lib/active_record/test_fixtures.rb +37 -16
  182. data/lib/active_record/timestamp.rb +4 -6
  183. data/lib/active_record/touch_later.rb +21 -21
  184. data/lib/active_record/transactions.rb +15 -64
  185. data/lib/active_record/type.rb +8 -1
  186. data/lib/active_record/type/serialized.rb +6 -2
  187. data/lib/active_record/type/time.rb +10 -0
  188. data/lib/active_record/type_caster/connection.rb +0 -1
  189. data/lib/active_record/type_caster/map.rb +8 -5
  190. data/lib/active_record/validations.rb +1 -0
  191. data/lib/active_record/validations/numericality.rb +35 -0
  192. data/lib/active_record/validations/uniqueness.rb +24 -4
  193. data/lib/arel.rb +5 -13
  194. data/lib/arel/attributes/attribute.rb +4 -0
  195. data/lib/arel/collectors/bind.rb +5 -0
  196. data/lib/arel/collectors/composite.rb +8 -0
  197. data/lib/arel/collectors/sql_string.rb +7 -0
  198. data/lib/arel/collectors/substitute_binds.rb +7 -0
  199. data/lib/arel/nodes.rb +3 -1
  200. data/lib/arel/nodes/binary.rb +82 -8
  201. data/lib/arel/nodes/bind_param.rb +8 -0
  202. data/lib/arel/nodes/casted.rb +21 -9
  203. data/lib/arel/nodes/equality.rb +6 -9
  204. data/lib/arel/nodes/grouping.rb +3 -0
  205. data/lib/arel/nodes/homogeneous_in.rb +72 -0
  206. data/lib/arel/nodes/in.rb +8 -1
  207. data/lib/arel/nodes/infix_operation.rb +13 -1
  208. data/lib/arel/nodes/join_source.rb +1 -1
  209. data/lib/arel/nodes/node.rb +7 -6
  210. data/lib/arel/nodes/ordering.rb +27 -0
  211. data/lib/arel/nodes/sql_literal.rb +3 -0
  212. data/lib/arel/nodes/table_alias.rb +7 -3
  213. data/lib/arel/nodes/unary.rb +0 -1
  214. data/lib/arel/predications.rb +12 -18
  215. data/lib/arel/select_manager.rb +1 -2
  216. data/lib/arel/table.rb +13 -5
  217. data/lib/arel/visitors.rb +0 -7
  218. data/lib/arel/visitors/dot.rb +14 -2
  219. data/lib/arel/visitors/mysql.rb +11 -1
  220. data/lib/arel/visitors/postgresql.rb +15 -4
  221. data/lib/arel/visitors/to_sql.rb +89 -78
  222. data/lib/rails/generators/active_record/migration.rb +6 -1
  223. data/lib/rails/generators/active_record/migration/migration_generator.rb +1 -0
  224. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +2 -0
  225. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +3 -3
  226. data/lib/rails/generators/active_record/model/model_generator.rb +39 -2
  227. data/lib/rails/generators/active_record/model/templates/abstract_base_class.rb.tt +7 -0
  228. metadata +27 -28
  229. data/lib/active_record/advisory_lock_base.rb +0 -18
  230. data/lib/active_record/attribute_decorators.rb +0 -88
  231. data/lib/active_record/connection_adapters/connection_specification.rb +0 -296
  232. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +0 -29
  233. data/lib/active_record/define_callbacks.rb +0 -22
  234. data/lib/active_record/railties/collection_cache_association_loading.rb +0 -34
  235. data/lib/active_record/relation/predicate_builder/base_handler.rb +0 -18
  236. data/lib/active_record/relation/where_clause_factory.rb +0 -33
  237. data/lib/arel/attributes.rb +0 -22
  238. data/lib/arel/visitors/depth_first.rb +0 -203
  239. data/lib/arel/visitors/ibm_db.rb +0 -34
  240. data/lib/arel/visitors/informix.rb +0 -62
  241. data/lib/arel/visitors/mssql.rb +0 -156
  242. data/lib/arel/visitors/oracle.rb +0 -158
  243. data/lib/arel/visitors/oracle12.rb +0 -65
  244. data/lib/arel/visitors/where_sql.rb +0 -22
@@ -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
  class InsertAll # :nodoc:
5
7
  attr_reader :model, :connection, :inserts, :keys
@@ -8,13 +10,19 @@ module ActiveRecord
8
10
  def initialize(model, inserts, on_duplicate:, returning: nil, unique_by: nil)
9
11
  raise ArgumentError, "Empty list of attributes passed" if inserts.blank?
10
12
 
11
- @model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s).to_set
13
+ @model, @connection, @inserts, @keys = model, model.connection, inserts, inserts.first.keys.map(&:to_s)
12
14
  @on_duplicate, @returning, @unique_by = on_duplicate, returning, unique_by
13
15
 
16
+ if model.scope_attributes?
17
+ @scope_attributes = model.scope_attributes
18
+ @keys |= @scope_attributes.keys
19
+ end
20
+ @keys = @keys.to_set
21
+
14
22
  @returning = (connection.supports_insert_returning? ? primary_keys : false) if @returning.nil?
15
23
  @returning = false if @returning == []
16
24
 
17
- @unique_by = find_unique_index_for(unique_by) if unique_by
25
+ @unique_by = find_unique_index_for(unique_by)
18
26
  @on_duplicate = :skip if @on_duplicate == :update && updatable_columns.empty?
19
27
 
20
28
  ensure_valid_options_for_connection!
@@ -32,7 +40,7 @@ module ActiveRecord
32
40
  end
33
41
 
34
42
  def primary_keys
35
- Array(model.primary_key)
43
+ Array(connection.schema_cache.primary_keys(model.table_name))
36
44
  end
37
45
 
38
46
 
@@ -47,6 +55,8 @@ module ActiveRecord
47
55
  def map_key_with_value
48
56
  inserts.map do |attributes|
49
57
  attributes = attributes.stringify_keys
58
+ attributes.merge!(scope_attributes) if scope_attributes
59
+
50
60
  verify_attributes(attributes)
51
61
 
52
62
  keys.map do |key|
@@ -56,13 +66,20 @@ module ActiveRecord
56
66
  end
57
67
 
58
68
  private
69
+ attr_reader :scope_attributes
70
+
59
71
  def find_unique_index_for(unique_by)
60
- match = Array(unique_by).map(&:to_s)
72
+ return unique_by if !connection.supports_insert_conflict_target?
73
+
74
+ name_or_columns = unique_by || model.primary_key
75
+ match = Array(name_or_columns).map(&:to_s)
61
76
 
62
77
  if index = unique_indexes.find { |i| match.include?(i.name) || i.columns == match }
63
78
  index
79
+ elsif match == primary_keys
80
+ unique_by.nil? ? nil : ActiveRecord::ConnectionAdapters::IndexDefinition.new(model.table_name, "#{model.table_name}_primary_key", true, match)
64
81
  else
65
- raise ArgumentError, "No unique index found for #{unique_by}"
82
+ raise ArgumentError, "No unique index found for #{name_or_columns}"
66
83
  end
67
84
  end
68
85
 
@@ -151,9 +168,21 @@ module ActiveRecord
151
168
  quote_columns(insert_all.updatable_columns)
152
169
  end
153
170
 
171
+ def touch_model_timestamps_unless(&block)
172
+ model.send(:timestamp_attributes_for_update_in_model).map do |column_name|
173
+ if touch_timestamp_attribute?(column_name)
174
+ "#{column_name}=(CASE WHEN (#{updatable_columns.map(&block).join(" AND ")}) THEN #{model.quoted_table_name}.#{column_name} ELSE CURRENT_TIMESTAMP END),"
175
+ end
176
+ end.compact.join
177
+ end
178
+
154
179
  private
155
180
  attr_reader :connection, :insert_all
156
181
 
182
+ def touch_timestamp_attribute?(column_name)
183
+ update_duplicates? && !insert_all.updatable_columns.include?(column_name)
184
+ end
185
+
157
186
  def columns_list
158
187
  format_columns(insert_all.keys)
159
188
  end
@@ -168,7 +197,7 @@ module ActiveRecord
168
197
  end
169
198
 
170
199
  def format_columns(columns)
171
- quote_columns(columns).join(",")
200
+ columns.respond_to?(:map) ? quote_columns(columns).join(",") : columns
172
201
  end
173
202
 
174
203
  def quote_columns(columns)
@@ -93,7 +93,7 @@ module ActiveRecord
93
93
  # cache_version, but this method can be overwritten to return something else.
94
94
  #
95
95
  # Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
96
- # +false+ (which it is by default until Rails 6.0).
96
+ # +false+.
97
97
  def cache_version
98
98
  return unless cache_versioning
99
99
 
@@ -104,10 +104,8 @@ module ActiveRecord
104
104
  elsif timestamp = updated_at
105
105
  timestamp.utc.to_s(cache_timestamp_format)
106
106
  end
107
- else
108
- if self.class.has_attribute?("updated_at")
109
- raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
110
- end
107
+ elsif self.class.has_attribute?("updated_at")
108
+ raise ActiveModel::MissingAttributeError, "missing attribute: updated_at"
111
109
  end
112
110
  end
113
111
 
@@ -6,8 +6,15 @@ require "active_record/scoping/named"
6
6
  module ActiveRecord
7
7
  # This class is used to create a table that keeps track of values and keys such
8
8
  # as which environment migrations were run in.
9
+ #
10
+ # This is enabled by default. To disable this functionality set
11
+ # `use_metadata_table` to false in your database configuration.
9
12
  class InternalMetadata < ActiveRecord::Base # :nodoc:
10
13
  class << self
14
+ def enabled?
15
+ ActiveRecord::Base.connection.use_metadata_table?
16
+ end
17
+
11
18
  def _internal?
12
19
  true
13
20
  end
@@ -21,24 +28,24 @@ module ActiveRecord
21
28
  end
22
29
 
23
30
  def []=(key, value)
31
+ return unless enabled?
32
+
24
33
  find_or_initialize_by(key: key).update!(value: value)
25
34
  end
26
35
 
27
36
  def [](key)
28
- where(key: key).pluck(:value).first
29
- end
37
+ return unless enabled?
30
38
 
31
- def table_exists?
32
- connection.table_exists?(table_name)
39
+ where(key: key).pluck(:value).first
33
40
  end
34
41
 
35
42
  # Creates an internal metadata table with columns +key+ and +value+
36
43
  def create_table
37
- unless table_exists?
38
- key_options = connection.internal_string_options_for_primary_key
44
+ return unless enabled?
39
45
 
46
+ unless connection.table_exists?(table_name)
40
47
  connection.create_table(table_name, id: false) do |t|
41
- t.string :key, **key_options
48
+ t.string :key, **connection.internal_string_options_for_primary_key
42
49
  t.string :value
43
50
  t.timestamps
44
51
  end
@@ -46,6 +53,8 @@ module ActiveRecord
46
53
  end
47
54
 
48
55
  def drop_table
56
+ return unless enabled?
57
+
49
58
  connection.drop_table table_name, if_exists: true
50
59
  end
51
60
  end
@@ -1,13 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
- module LegacyYamlAdapter
4
+ module LegacyYamlAdapter # :nodoc:
5
5
  def self.convert(klass, coder)
6
6
  return coder unless coder.is_a?(Psych::Coder)
7
7
 
8
8
  case coder["active_record_yaml_version"]
9
9
  when 1, 2 then coder
10
10
  else
11
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
12
+ YAML loading from legacy format older than Rails 5.0 is deprecated
13
+ and will be removed in Rails 6.2.
14
+ MSG
11
15
  if coder["attributes"].is_a?(ActiveModel::AttributeSet)
12
16
  Rails420.convert(klass, coder)
13
17
  else
@@ -16,7 +20,7 @@ module ActiveRecord
16
20
  end
17
21
  end
18
22
 
19
- module Rails420
23
+ module Rails420 # :nodoc:
20
24
  def self.convert(klass, coder)
21
25
  attribute_set = coder["attributes"]
22
26
 
@@ -32,7 +36,7 @@ module ActiveRecord
32
36
  end
33
37
  end
34
38
 
35
- module Rails41
39
+ module Rails41 # :nodoc:
36
40
  def self.convert(klass, coder)
37
41
  attributes = klass.attributes_builder
38
42
  .build_from_database(coder["attributes"])
@@ -60,6 +60,15 @@ module ActiveRecord
60
60
  self.class.locking_enabled?
61
61
  end
62
62
 
63
+ def increment!(*, **) #:nodoc:
64
+ super.tap do
65
+ if locking_enabled?
66
+ self[self.class.locking_column] += 1
67
+ clear_attribute_change(self.class.locking_column)
68
+ end
69
+ end
70
+ end
71
+
63
72
  private
64
73
  def _create_record(attribute_names = self.attribute_names)
65
74
  if locking_enabled?
@@ -80,7 +89,8 @@ module ActiveRecord
80
89
 
81
90
  begin
82
91
  locking_column = self.class.locking_column
83
- previous_lock_value = read_attribute_before_type_cast(locking_column)
92
+ previous_lock_value = attribute_before_type_cast(locking_column)
93
+ attribute_names = attribute_names.dup if attribute_names.frozen?
84
94
  attribute_names << locking_column
85
95
 
86
96
  self[locking_column] += 1
@@ -88,7 +98,7 @@ module ActiveRecord
88
98
  affected_rows = self.class._update_record(
89
99
  attributes_with_values(attribute_names),
90
100
  @primary_key => id_in_database,
91
- locking_column => previous_lock_value
101
+ locking_column => @attributes[locking_column].original_value_for_database
92
102
  )
93
103
 
94
104
  if affected_rows != 1
@@ -111,7 +121,7 @@ module ActiveRecord
111
121
 
112
122
  affected_rows = self.class._delete_record(
113
123
  @primary_key => id_in_database,
114
- locking_column => read_attribute_before_type_cast(locking_column)
124
+ locking_column => attribute_before_type_cast(locking_column)
115
125
  )
116
126
 
117
127
  if affected_rows != 1
@@ -155,20 +165,12 @@ module ActiveRecord
155
165
  super
156
166
  end
157
167
 
158
- private
159
- # We need to apply this decorator here, rather than on module inclusion. The closure
160
- # created by the matcher would otherwise evaluate for `ActiveRecord::Base`, not the
161
- # sub class being decorated. As such, changes to `lock_optimistically`, or
162
- # `locking_column` would not be picked up.
163
- def inherited(subclass)
164
- subclass.class_eval do
165
- is_lock_column = ->(name, _) { lock_optimistically && name == locking_column }
166
- decorate_matching_attribute_types(is_lock_column, "_optimistic_locking") do |type|
167
- LockingType.new(type)
168
- end
169
- end
170
- super
168
+ def define_attribute(name, cast_type, **) # :nodoc:
169
+ if lock_optimistically && name == locking_column
170
+ cast_type = LockingType.new(cast_type)
171
171
  end
172
+ super
173
+ end
172
174
  end
173
175
  end
174
176
 
@@ -176,6 +178,10 @@ module ActiveRecord
176
178
  # `nil` values to `lock_version`, and not result in `ActiveRecord::StaleObjectError`
177
179
  # during update record.
178
180
  class LockingType < DelegateClass(Type::Value) # :nodoc:
181
+ def self.new(subtype)
182
+ self === subtype ? subtype : super
183
+ end
184
+
179
185
  def deserialize(value)
180
186
  super.to_i
181
187
  end
@@ -53,8 +53,12 @@ module ActiveRecord
53
53
  # end
54
54
  #
55
55
  # Database-specific information on row locking:
56
- # MySQL: https://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
57
- # PostgreSQL: https://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
56
+ #
57
+ # [MySQL]
58
+ # https://dev.mysql.com/doc/refman/en/innodb-locking-reads.html
59
+ #
60
+ # [PostgreSQL]
61
+ # https://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
58
62
  module Pessimistic
59
63
  # Obtain a row lock on this record. Reloads the record to obtain the requested
60
64
  # lock. Pass an SQL locking clause to append the end of the SELECT statement
@@ -19,6 +19,15 @@ module ActiveRecord
19
19
  rt
20
20
  end
21
21
 
22
+ def strict_loading_violation(event)
23
+ debug do
24
+ owner = event.payload[:owner]
25
+ association = event.payload[:association]
26
+
27
+ color("Strict loading violation: #{association} lazily loaded on #{owner}.", RED)
28
+ end
29
+ end
30
+
22
31
  def sql(event)
23
32
  self.class.runtime += event.duration
24
33
  return unless logger.debug?
@@ -32,11 +41,15 @@ module ActiveRecord
32
41
  sql = payload[:sql]
33
42
  binds = nil
34
43
 
35
- unless (payload[:binds] || []).empty?
44
+ if payload[:binds]&.any?
36
45
  casted_params = type_casted_binds(payload[:type_casted_binds])
37
- binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
38
- render_bind(attr, value)
39
- }.inspect
46
+
47
+ binds = []
48
+ payload[:binds].each_with_index do |attr, i|
49
+ binds << render_bind(attr, casted_params[i])
50
+ end
51
+ binds = binds.inspect
52
+ binds.prepend(" ")
40
53
  end
41
54
 
42
55
  name = colorize_payload_name(name, payload[:name])
@@ -51,13 +64,18 @@ module ActiveRecord
51
64
  end
52
65
 
53
66
  def render_bind(attr, value)
54
- if attr.is_a?(Array)
67
+ case attr
68
+ when ActiveModel::Attribute
69
+ if attr.type.binary? && attr.value
70
+ value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
71
+ end
72
+ when Array
55
73
  attr = attr.first
56
- elsif attr.type.binary? && attr.value
57
- value = "<#{attr.value_for_database.to_s.bytesize} bytes of binary data>"
74
+ else
75
+ attr = nil
58
76
  end
59
77
 
60
- [attr && attr.name, value]
78
+ [attr&.name, value]
61
79
  end
62
80
 
63
81
  def colorize_payload_name(name, payload_name)
@@ -59,11 +59,14 @@ module ActiveRecord
59
59
  context = context_klass.call(request)
60
60
  resolver = resolver_klass.call(context, options)
61
61
 
62
- if reading_request?(request)
62
+ response = if reading_request?(request)
63
63
  resolver.read(&blk)
64
64
  else
65
65
  resolver.write(&blk)
66
66
  end
67
+
68
+ resolver.update_context(response)
69
+ response
67
70
  end
68
71
 
69
72
  def reading_request?(request)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_record/middleware/database_selector/resolver/session"
4
+ require "active_support/core_ext/numeric/time"
4
5
 
5
6
  module ActiveRecord
6
7
  module Middleware
@@ -43,6 +44,10 @@ module ActiveRecord
43
44
  write_to_primary(&blk)
44
45
  end
45
46
 
47
+ def update_context(response)
48
+ context.save(response)
49
+ end
50
+
46
51
  private
47
52
  def read_from_primary(&blk)
48
53
  ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role, prevent_writes: true) do
@@ -38,6 +38,9 @@ module ActiveRecord
38
38
  def update_last_write_timestamp
39
39
  session[:last_write] = self.class.convert_time_to_timestamp(Time.now)
40
40
  end
41
+
42
+ def save(response)
43
+ end
41
44
  end
42
45
  end
43
46
  end
@@ -3,6 +3,8 @@
3
3
  require "benchmark"
4
4
  require "set"
5
5
  require "zlib"
6
+ require "active_support/core_ext/array/access"
7
+ require "active_support/core_ext/enumerable"
6
8
  require "active_support/core_ext/module/attribute_accessors"
7
9
  require "active_support/actionable_error"
8
10
 
@@ -18,7 +20,7 @@ module ActiveRecord
18
20
  # For example the following migration is not reversible.
19
21
  # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
20
22
  #
21
- # class IrreversibleMigrationExample < ActiveRecord::Migration[5.0]
23
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[6.0]
22
24
  # def change
23
25
  # create_table :distributors do |t|
24
26
  # t.string :zipcode
@@ -36,7 +38,7 @@ module ActiveRecord
36
38
  #
37
39
  # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
38
40
  #
39
- # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
41
+ # class ReversibleMigrationExample < ActiveRecord::Migration[6.0]
40
42
  # def up
41
43
  # create_table :distributors do |t|
42
44
  # t.string :zipcode
@@ -61,7 +63,7 @@ module ActiveRecord
61
63
  #
62
64
  # 2. Use the #reversible method in <tt>#change</tt> method:
63
65
  #
64
- # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
66
+ # class ReversibleMigrationExample < ActiveRecord::Migration[6.0]
65
67
  # def change
66
68
  # create_table :distributors do |t|
67
69
  # t.string :zipcode
@@ -133,17 +135,34 @@ module ActiveRecord
133
135
 
134
136
  action "Run pending migrations" do
135
137
  ActiveRecord::Tasks::DatabaseTasks.migrate
138
+
139
+ if ActiveRecord::Base.dump_schema_after_migration
140
+ ActiveRecord::Tasks::DatabaseTasks.dump_schema(
141
+ ActiveRecord::Base.connection_db_config
142
+ )
143
+ end
136
144
  end
137
145
 
138
146
  def initialize(message = nil)
139
- if !message && defined?(Rails.env)
140
- super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate RAILS_ENV=#{::Rails.env}")
141
- elsif !message
142
- super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate")
143
- else
144
- super
145
- end
147
+ super(message || detailed_migration_message)
146
148
  end
149
+
150
+ private
151
+ def detailed_migration_message
152
+ message = "Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate"
153
+ message += " RAILS_ENV=#{::Rails.env}" if defined?(Rails.env)
154
+ message += "\n\n"
155
+
156
+ pending_migrations = ActiveRecord::Base.connection.migration_context.open.pending_migrations
157
+
158
+ message += "You have #{pending_migrations.size} pending #{pending_migrations.size > 1 ? 'migrations:' : 'migration:'}\n\n"
159
+
160
+ pending_migrations.each do |pending_migration|
161
+ message += "#{pending_migration.basename}\n"
162
+ end
163
+
164
+ message
165
+ end
147
166
  end
148
167
 
149
168
  class ConcurrentMigrationError < MigrationError #:nodoc:
@@ -157,7 +176,7 @@ module ActiveRecord
157
176
 
158
177
  class NoEnvironmentInSchemaError < MigrationError #:nodoc:
159
178
  def initialize
160
- msg = "Environment data not found in the schema. To resolve this issue, run: \n\n rails db:environment:set"
179
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
161
180
  if defined?(Rails.env)
162
181
  super("#{msg} RAILS_ENV=#{::Rails.env}")
163
182
  else
@@ -180,7 +199,7 @@ module ActiveRecord
180
199
  msg = +"You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
181
200
  msg << "You are running in `#{ current }` environment. "
182
201
  msg << "If you are sure you want to continue, first set the environment using:\n\n"
183
- msg << " rails db:environment:set"
202
+ msg << " bin/rails db:environment:set"
184
203
  if defined?(Rails.env)
185
204
  super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
186
205
  else
@@ -189,6 +208,14 @@ module ActiveRecord
189
208
  end
190
209
  end
191
210
 
211
+ class EnvironmentStorageError < ActiveRecordError # :nodoc:
212
+ def initialize
213
+ msg = +"You are attempting to store the environment in a database where metadata is disabled.\n"
214
+ msg << "Check your database configuration to see if this is intended."
215
+ super(msg)
216
+ end
217
+ end
218
+
192
219
  # = Active Record Migrations
193
220
  #
194
221
  # Migrations can manage the evolution of a schema used by several physical
@@ -201,7 +228,7 @@ module ActiveRecord
201
228
  #
202
229
  # Example of a simple migration:
203
230
  #
204
- # class AddSsl < ActiveRecord::Migration[5.0]
231
+ # class AddSsl < ActiveRecord::Migration[6.0]
205
232
  # def up
206
233
  # add_column :accounts, :ssl_enabled, :boolean, default: true
207
234
  # end
@@ -221,7 +248,7 @@ module ActiveRecord
221
248
  #
222
249
  # Example of a more complex migration that also needs to initialize data:
223
250
  #
224
- # class AddSystemSettings < ActiveRecord::Migration[5.0]
251
+ # class AddSystemSettings < ActiveRecord::Migration[6.0]
225
252
  # def up
226
253
  # create_table :system_settings do |t|
227
254
  # t.string :name
@@ -337,7 +364,7 @@ module ActiveRecord
337
364
  # The Rails package has several tools to help create and apply migrations.
338
365
  #
339
366
  # To generate a new migration, you can use
340
- # rails generate migration MyNewMigration
367
+ # bin/rails generate migration MyNewMigration
341
368
  #
342
369
  # where MyNewMigration is the name of your migration. The generator will
343
370
  # create an empty migration file <tt>timestamp_my_new_migration.rb</tt>
@@ -346,41 +373,36 @@ module ActiveRecord
346
373
  #
347
374
  # There is a special syntactic shortcut to generate migrations that add fields to a table.
348
375
  #
349
- # rails generate migration add_fieldname_to_tablename fieldname:string
376
+ # bin/rails generate migration add_fieldname_to_tablename fieldname:string
350
377
  #
351
378
  # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
352
- # class AddFieldnameToTablename < ActiveRecord::Migration[5.0]
379
+ # class AddFieldnameToTablename < ActiveRecord::Migration[6.0]
353
380
  # def change
354
381
  # add_column :tablenames, :fieldname, :string
355
382
  # end
356
383
  # end
357
384
  #
358
385
  # To run migrations against the currently configured database, use
359
- # <tt>rails db:migrate</tt>. This will update the database by running all of the
386
+ # <tt>bin/rails db:migrate</tt>. This will update the database by running all of the
360
387
  # pending migrations, creating the <tt>schema_migrations</tt> table
361
388
  # (see "About the schema_migrations table" section below) if missing. It will also
362
389
  # invoke the db:schema:dump command, which will update your db/schema.rb file
363
390
  # to match the structure of your database.
364
391
  #
365
392
  # To roll the database back to a previous migration version, use
366
- # <tt>rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
393
+ # <tt>bin/rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
367
394
  # you wish to downgrade. Alternatively, you can also use the STEP option if you
368
- # wish to rollback last few migrations. <tt>rails db:rollback STEP=2</tt> will rollback
395
+ # wish to rollback last few migrations. <tt>bin/rails db:rollback STEP=2</tt> will rollback
369
396
  # the latest two migrations.
370
397
  #
371
398
  # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
372
399
  # that step will fail and you'll have some manual work to do.
373
400
  #
374
- # == Database support
375
- #
376
- # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
377
- # SQL Server, and Oracle (all supported databases except DB2).
378
- #
379
401
  # == More examples
380
402
  #
381
403
  # Not all migrations change the schema. Some just fix the data:
382
404
  #
383
- # class RemoveEmptyTags < ActiveRecord::Migration[5.0]
405
+ # class RemoveEmptyTags < ActiveRecord::Migration[6.0]
384
406
  # def up
385
407
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
386
408
  # end
@@ -393,7 +415,7 @@ module ActiveRecord
393
415
  #
394
416
  # Others remove columns when they migrate up instead of down:
395
417
  #
396
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[5.0]
418
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[6.0]
397
419
  # def up
398
420
  # remove_column :items, :incomplete_items_count
399
421
  # remove_column :items, :completed_items_count
@@ -407,7 +429,7 @@ module ActiveRecord
407
429
  #
408
430
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
409
431
  #
410
- # class MakeJoinUnique < ActiveRecord::Migration[5.0]
432
+ # class MakeJoinUnique < ActiveRecord::Migration[6.0]
411
433
  # def up
412
434
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
413
435
  # end
@@ -424,7 +446,7 @@ module ActiveRecord
424
446
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
425
447
  # latest column data from after the new column was added. Example:
426
448
  #
427
- # class AddPeopleSalary < ActiveRecord::Migration[5.0]
449
+ # class AddPeopleSalary < ActiveRecord::Migration[6.0]
428
450
  # def up
429
451
  # add_column :people, :salary, :integer
430
452
  # Person.reset_column_information
@@ -482,7 +504,7 @@ module ActiveRecord
482
504
  # To define a reversible migration, define the +change+ method in your
483
505
  # migration like this:
484
506
  #
485
- # class TenderloveMigration < ActiveRecord::Migration[5.0]
507
+ # class TenderloveMigration < ActiveRecord::Migration[6.0]
486
508
  # def change
487
509
  # create_table(:horses) do |t|
488
510
  # t.column :content, :text
@@ -512,7 +534,7 @@ module ActiveRecord
512
534
  # can't execute inside a transaction though, and for these situations
513
535
  # you can turn the automatic transactions off.
514
536
  #
515
- # class ChangeEnum < ActiveRecord::Migration[5.0]
537
+ # class ChangeEnum < ActiveRecord::Migration[6.0]
516
538
  # disable_ddl_transaction!
517
539
  #
518
540
  # def up
@@ -525,6 +547,7 @@ module ActiveRecord
525
547
  class Migration
526
548
  autoload :CommandRecorder, "active_record/migration/command_recorder"
527
549
  autoload :Compatibility, "active_record/migration/compatibility"
550
+ autoload :JoinTable, "active_record/migration/join_table"
528
551
 
529
552
  # This must be defined before the inherited hook, below
530
553
  class Current < Migration #:nodoc:
@@ -553,21 +576,37 @@ module ActiveRecord
553
576
  # This class is used to verify that all migrations have been run before
554
577
  # loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
555
578
  class CheckPending
556
- def initialize(app)
579
+ def initialize(app, file_watcher: ActiveSupport::FileUpdateChecker)
557
580
  @app = app
558
- @last_check = 0
581
+ @needs_check = true
582
+ @mutex = Mutex.new
583
+ @file_watcher = file_watcher
559
584
  end
560
585
 
561
586
  def call(env)
562
- mtime = ActiveRecord::Base.connection.migration_context.last_migration.mtime.to_i
563
- if @last_check < mtime
564
- ActiveRecord::Migration.check_pending!(connection)
565
- @last_check = mtime
587
+ @mutex.synchronize do
588
+ @watcher ||= build_watcher do
589
+ @needs_check = true
590
+ ActiveRecord::Migration.check_pending!(connection)
591
+ @needs_check = false
592
+ end
593
+
594
+ if @needs_check
595
+ @watcher.execute
596
+ else
597
+ @watcher.execute_if_updated
598
+ end
566
599
  end
600
+
567
601
  @app.call(env)
568
602
  end
569
603
 
570
604
  private
605
+ def build_watcher(&block)
606
+ paths = Array(connection.migration_context.migrations_paths)
607
+ @file_watcher.new([], paths.index_with(["rb"]), &block)
608
+ end
609
+
571
610
  def connection
572
611
  ActiveRecord::Base.connection
573
612
  end
@@ -587,11 +626,11 @@ module ActiveRecord
587
626
  end
588
627
 
589
628
  def load_schema_if_pending!
590
- current_config = Base.connection_config
629
+ current_db_config = Base.connection_db_config
591
630
  all_configs = ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
592
631
 
593
632
  needs_update = !all_configs.all? do |db_config|
594
- Tasks::DatabaseTasks.schema_up_to_date?(db_config.config, ActiveRecord::Base.schema_format, nil, Rails.env, db_config.spec_name)
633
+ Tasks::DatabaseTasks.schema_up_to_date?(db_config, ActiveRecord::Base.schema_format)
595
634
  end
596
635
 
597
636
  if needs_update
@@ -604,7 +643,7 @@ module ActiveRecord
604
643
  end
605
644
 
606
645
  # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
607
- Base.establish_connection(current_config)
646
+ Base.establish_connection(current_db_config)
608
647
 
609
648
  check_pending!
610
649
  end
@@ -657,7 +696,7 @@ module ActiveRecord
657
696
  # and create the table 'apples' on the way up, and the reverse
658
697
  # on the way down.
659
698
  #
660
- # class FixTLMigration < ActiveRecord::Migration[5.0]
699
+ # class FixTLMigration < ActiveRecord::Migration[6.0]
661
700
  # def change
662
701
  # revert do
663
702
  # create_table(:horses) do |t|
@@ -674,9 +713,9 @@ module ActiveRecord
674
713
  # Or equivalently, if +TenderloveMigration+ is defined as in the
675
714
  # documentation for Migration:
676
715
  #
677
- # require_relative '20121212123456_tenderlove_migration'
716
+ # require_relative "20121212123456_tenderlove_migration"
678
717
  #
679
- # class FixupTLMigration < ActiveRecord::Migration[5.0]
718
+ # class FixupTLMigration < ActiveRecord::Migration[6.0]
680
719
  # def change
681
720
  # revert TenderloveMigration
682
721
  #
@@ -727,7 +766,7 @@ module ActiveRecord
727
766
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
728
767
  # even when migrating down:
729
768
  #
730
- # class SplitNameMigration < ActiveRecord::Migration[5.0]
769
+ # class SplitNameMigration < ActiveRecord::Migration[6.0]
731
770
  # def change
732
771
  # add_column :users, :first_name, :string
733
772
  # add_column :users, :last_name, :string
@@ -755,7 +794,7 @@ module ActiveRecord
755
794
  # In the following example, the new column +published+ will be given
756
795
  # the value +true+ for all existing records.
757
796
  #
758
- # class AddPublishedToPosts < ActiveRecord::Migration[5.2]
797
+ # class AddPublishedToPosts < ActiveRecord::Migration[6.0]
759
798
  # def change
760
799
  # add_column :posts, :published, :boolean, default: false
761
800
  # up_only do
@@ -828,7 +867,7 @@ module ActiveRecord
828
867
  change
829
868
  end
830
869
  else
831
- send(direction)
870
+ public_send(direction)
832
871
  end
833
872
  ensure
834
873
  @connection = nil
@@ -995,10 +1034,6 @@ module ActiveRecord
995
1034
  File.basename(filename)
996
1035
  end
997
1036
 
998
- def mtime
999
- File.mtime filename
1000
- end
1001
-
1002
1037
  delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
1003
1038
 
1004
1039
  private
@@ -1012,16 +1047,6 @@ module ActiveRecord
1012
1047
  end
1013
1048
  end
1014
1049
 
1015
- class NullMigration < MigrationProxy #:nodoc:
1016
- def initialize
1017
- super(nil, 0, nil, nil)
1018
- end
1019
-
1020
- def mtime
1021
- 0
1022
- end
1023
- end
1024
-
1025
1050
  class MigrationContext #:nodoc:
1026
1051
  attr_reader :migrations_paths, :schema_migration
1027
1052
 
@@ -1100,10 +1125,6 @@ module ActiveRecord
1100
1125
  migrations.any?
1101
1126
  end
1102
1127
 
1103
- def last_migration #:nodoc:
1104
- migrations.last || NullMigration.new
1105
- end
1106
-
1107
1128
  def migrations
1108
1129
  migrations = migration_files.map do |file|
1109
1130
  version, name, scope = parse_migration_filename(file)
@@ -1144,6 +1165,7 @@ module ActiveRecord
1144
1165
  end
1145
1166
 
1146
1167
  def last_stored_environment
1168
+ return nil unless ActiveRecord::InternalMetadata.enabled?
1147
1169
  return nil if current_version == 0
1148
1170
  raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1149
1171
 
@@ -1178,7 +1200,7 @@ module ActiveRecord
1178
1200
 
1179
1201
  finish = migrator.migrations[start_index + steps]
1180
1202
  version = finish ? finish.version : 0
1181
- send(direction, version)
1203
+ public_send(direction, version)
1182
1204
  end
1183
1205
  end
1184
1206
 
@@ -1265,7 +1287,7 @@ module ActiveRecord
1265
1287
  def run_without_lock
1266
1288
  migration = migrations.detect { |m| m.version == @target_version }
1267
1289
  raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1268
- result = execute_migration_in_transaction(migration, @direction)
1290
+ result = execute_migration_in_transaction(migration)
1269
1291
 
1270
1292
  record_environment
1271
1293
  result
@@ -1277,10 +1299,7 @@ module ActiveRecord
1277
1299
  raise UnknownMigrationVersionError.new(@target_version)
1278
1300
  end
1279
1301
 
1280
- result = runnable.each do |migration|
1281
- execute_migration_in_transaction(migration, @direction)
1282
- end
1283
-
1302
+ result = runnable.each(&method(:execute_migration_in_transaction))
1284
1303
  record_environment
1285
1304
  result
1286
1305
  end
@@ -1300,14 +1319,14 @@ module ActiveRecord
1300
1319
  @target_version && @target_version != 0 && !target
1301
1320
  end
1302
1321
 
1303
- def execute_migration_in_transaction(migration, direction)
1322
+ def execute_migration_in_transaction(migration)
1304
1323
  return if down? && !migrated.include?(migration.version.to_i)
1305
1324
  return if up? && migrated.include?(migration.version.to_i)
1306
1325
 
1307
1326
  Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1308
1327
 
1309
1328
  ddl_transaction(migration) do
1310
- migration.migrate(direction)
1329
+ migration.migrate(@direction)
1311
1330
  record_version_state_after_migrating(migration.version)
1312
1331
  end
1313
1332
  rescue => e
@@ -1374,20 +1393,31 @@ module ActiveRecord
1374
1393
 
1375
1394
  def with_advisory_lock
1376
1395
  lock_id = generate_migrator_advisory_lock_id
1377
- AdvisoryLockBase.establish_connection(ActiveRecord::Base.connection_config) unless AdvisoryLockBase.connected?
1378
- connection = AdvisoryLockBase.connection
1379
- got_lock = connection.get_advisory_lock(lock_id)
1380
- raise ConcurrentMigrationError unless got_lock
1381
- load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1382
- yield
1383
- ensure
1384
- if got_lock && !connection.release_advisory_lock(lock_id)
1385
- raise ConcurrentMigrationError.new(
1386
- ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1387
- )
1396
+
1397
+ with_advisory_lock_connection do |connection|
1398
+ got_lock = connection.get_advisory_lock(lock_id)
1399
+ raise ConcurrentMigrationError unless got_lock
1400
+ load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1401
+ yield
1402
+ ensure
1403
+ if got_lock && !connection.release_advisory_lock(lock_id)
1404
+ raise ConcurrentMigrationError.new(
1405
+ ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1406
+ )
1407
+ end
1388
1408
  end
1389
1409
  end
1390
1410
 
1411
+ def with_advisory_lock_connection
1412
+ pool = ActiveRecord::ConnectionAdapters::ConnectionHandler.new.establish_connection(
1413
+ ActiveRecord::Base.connection_db_config
1414
+ )
1415
+
1416
+ pool.with_connection { |connection| yield(connection) }
1417
+ ensure
1418
+ pool&.disconnect!
1419
+ end
1420
+
1391
1421
  MIGRATOR_SALT = 2053462845
1392
1422
  def generate_migrator_advisory_lock_id
1393
1423
  db_name_hash = Zlib.crc32(Base.connection.current_database)