activerecord 5.2.3 → 6.0.0.rc2

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 (266) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +605 -554
  3. data/MIT-LICENSE +3 -1
  4. data/README.rdoc +4 -2
  5. data/examples/performance.rb +1 -1
  6. data/lib/active_record.rb +9 -2
  7. data/lib/active_record/aggregations.rb +4 -2
  8. data/lib/active_record/associations.rb +19 -14
  9. data/lib/active_record/associations/association.rb +52 -19
  10. data/lib/active_record/associations/association_scope.rb +4 -6
  11. data/lib/active_record/associations/belongs_to_association.rb +36 -42
  12. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +0 -4
  13. data/lib/active_record/associations/builder/association.rb +14 -18
  14. data/lib/active_record/associations/builder/belongs_to.rb +19 -52
  15. data/lib/active_record/associations/builder/collection_association.rb +5 -15
  16. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +17 -38
  17. data/lib/active_record/associations/builder/has_many.rb +2 -0
  18. data/lib/active_record/associations/builder/has_one.rb +35 -1
  19. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  20. data/lib/active_record/associations/collection_association.rb +6 -21
  21. data/lib/active_record/associations/collection_proxy.rb +12 -15
  22. data/lib/active_record/associations/foreign_association.rb +7 -0
  23. data/lib/active_record/associations/has_many_association.rb +2 -10
  24. data/lib/active_record/associations/has_many_through_association.rb +18 -25
  25. data/lib/active_record/associations/has_one_association.rb +28 -30
  26. data/lib/active_record/associations/has_one_through_association.rb +5 -5
  27. data/lib/active_record/associations/join_dependency.rb +24 -28
  28. data/lib/active_record/associations/join_dependency/join_association.rb +27 -7
  29. data/lib/active_record/associations/join_dependency/join_part.rb +2 -2
  30. data/lib/active_record/associations/preloader.rb +39 -31
  31. data/lib/active_record/associations/preloader/association.rb +38 -36
  32. data/lib/active_record/associations/preloader/through_association.rb +48 -39
  33. data/lib/active_record/associations/singular_association.rb +2 -16
  34. data/lib/active_record/attribute_assignment.rb +7 -10
  35. data/lib/active_record/attribute_methods.rb +28 -100
  36. data/lib/active_record/attribute_methods/before_type_cast.rb +4 -1
  37. data/lib/active_record/attribute_methods/dirty.rb +111 -40
  38. data/lib/active_record/attribute_methods/primary_key.rb +15 -22
  39. data/lib/active_record/attribute_methods/query.rb +2 -3
  40. data/lib/active_record/attribute_methods/read.rb +15 -53
  41. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  42. data/lib/active_record/attribute_methods/time_zone_conversion.rb +1 -1
  43. data/lib/active_record/attribute_methods/write.rb +17 -24
  44. data/lib/active_record/attributes.rb +13 -0
  45. data/lib/active_record/autosave_association.rb +15 -5
  46. data/lib/active_record/base.rb +2 -3
  47. data/lib/active_record/callbacks.rb +5 -19
  48. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +111 -19
  49. data/lib/active_record/connection_adapters/abstract/database_limits.rb +17 -4
  50. data/lib/active_record/connection_adapters/abstract/database_statements.rb +95 -123
  51. data/lib/active_record/connection_adapters/abstract/query_cache.rb +20 -11
  52. data/lib/active_record/connection_adapters/abstract/quoting.rb +68 -17
  53. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +19 -12
  54. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +76 -48
  55. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +1 -3
  56. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +132 -53
  57. data/lib/active_record/connection_adapters/abstract/transaction.rb +96 -56
  58. data/lib/active_record/connection_adapters/abstract_adapter.rb +172 -41
  59. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +128 -194
  60. data/lib/active_record/connection_adapters/column.rb +17 -13
  61. data/lib/active_record/connection_adapters/connection_specification.rb +52 -42
  62. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +6 -10
  63. data/lib/active_record/connection_adapters/mysql/database_statements.rb +73 -13
  64. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -7
  65. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +3 -4
  66. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +40 -32
  67. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +14 -6
  68. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +129 -13
  69. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +6 -10
  70. data/lib/active_record/connection_adapters/mysql2_adapter.rb +24 -7
  71. data/lib/active_record/connection_adapters/postgresql/column.rb +17 -31
  72. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +20 -1
  73. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +1 -1
  74. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +1 -4
  75. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +1 -1
  76. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +1 -1
  77. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +1 -1
  78. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +1 -1
  79. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +9 -7
  80. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +6 -3
  81. data/lib/active_record/connection_adapters/postgresql/quoting.rb +44 -7
  82. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +12 -1
  83. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -91
  84. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +55 -53
  85. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +24 -27
  86. data/lib/active_record/connection_adapters/postgresql_adapter.rb +160 -74
  87. data/lib/active_record/connection_adapters/schema_cache.rb +37 -14
  88. data/lib/active_record/connection_adapters/sql_type_metadata.rb +11 -8
  89. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +118 -0
  90. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +42 -6
  91. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +42 -11
  92. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +127 -143
  93. data/lib/active_record/connection_handling.rb +149 -27
  94. data/lib/active_record/core.rb +100 -60
  95. data/lib/active_record/counter_cache.rb +4 -29
  96. data/lib/active_record/database_configurations.rb +204 -0
  97. data/lib/active_record/database_configurations/database_config.rb +37 -0
  98. data/lib/active_record/database_configurations/hash_config.rb +50 -0
  99. data/lib/active_record/database_configurations/url_config.rb +79 -0
  100. data/lib/active_record/dynamic_matchers.rb +1 -1
  101. data/lib/active_record/enum.rb +28 -7
  102. data/lib/active_record/errors.rb +15 -7
  103. data/lib/active_record/explain.rb +1 -1
  104. data/lib/active_record/fixture_set/model_metadata.rb +33 -0
  105. data/lib/active_record/fixture_set/render_context.rb +17 -0
  106. data/lib/active_record/fixture_set/table_row.rb +153 -0
  107. data/lib/active_record/fixture_set/table_rows.rb +47 -0
  108. data/lib/active_record/fixtures.rb +140 -472
  109. data/lib/active_record/gem_version.rb +4 -4
  110. data/lib/active_record/inheritance.rb +13 -3
  111. data/lib/active_record/insert_all.rb +180 -0
  112. data/lib/active_record/integration.rb +68 -16
  113. data/lib/active_record/internal_metadata.rb +10 -2
  114. data/lib/active_record/locking/optimistic.rb +5 -6
  115. data/lib/active_record/locking/pessimistic.rb +3 -3
  116. data/lib/active_record/log_subscriber.rb +7 -26
  117. data/lib/active_record/middleware/database_selector.rb +75 -0
  118. data/lib/active_record/middleware/database_selector/resolver.rb +90 -0
  119. data/lib/active_record/middleware/database_selector/resolver/session.rb +45 -0
  120. data/lib/active_record/migration.rb +87 -76
  121. data/lib/active_record/migration/command_recorder.rb +50 -6
  122. data/lib/active_record/migration/compatibility.rb +76 -49
  123. data/lib/active_record/model_schema.rb +30 -9
  124. data/lib/active_record/nested_attributes.rb +2 -2
  125. data/lib/active_record/no_touching.rb +7 -0
  126. data/lib/active_record/persistence.rb +228 -24
  127. data/lib/active_record/query_cache.rb +11 -4
  128. data/lib/active_record/querying.rb +32 -20
  129. data/lib/active_record/railtie.rb +80 -43
  130. data/lib/active_record/railties/collection_cache_association_loading.rb +34 -0
  131. data/lib/active_record/railties/controller_runtime.rb +30 -35
  132. data/lib/active_record/railties/databases.rake +193 -46
  133. data/lib/active_record/reflection.rb +42 -44
  134. data/lib/active_record/relation.rb +310 -80
  135. data/lib/active_record/relation/batches.rb +13 -10
  136. data/lib/active_record/relation/calculations.rb +58 -49
  137. data/lib/active_record/relation/delegation.rb +26 -43
  138. data/lib/active_record/relation/finder_methods.rb +14 -27
  139. data/lib/active_record/relation/merger.rb +11 -20
  140. data/lib/active_record/relation/predicate_builder.rb +4 -6
  141. data/lib/active_record/relation/predicate_builder/array_handler.rb +5 -4
  142. data/lib/active_record/relation/predicate_builder/association_query_value.rb +1 -4
  143. data/lib/active_record/relation/predicate_builder/base_handler.rb +1 -2
  144. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +1 -2
  145. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -4
  146. data/lib/active_record/relation/predicate_builder/range_handler.rb +3 -23
  147. data/lib/active_record/relation/query_attribute.rb +13 -8
  148. data/lib/active_record/relation/query_methods.rb +182 -68
  149. data/lib/active_record/relation/spawn_methods.rb +1 -1
  150. data/lib/active_record/relation/where_clause.rb +14 -10
  151. data/lib/active_record/relation/where_clause_factory.rb +1 -2
  152. data/lib/active_record/result.rb +30 -11
  153. data/lib/active_record/sanitization.rb +32 -40
  154. data/lib/active_record/schema.rb +2 -11
  155. data/lib/active_record/schema_dumper.rb +22 -7
  156. data/lib/active_record/schema_migration.rb +5 -1
  157. data/lib/active_record/scoping.rb +8 -8
  158. data/lib/active_record/scoping/default.rb +6 -7
  159. data/lib/active_record/scoping/named.rb +19 -15
  160. data/lib/active_record/statement_cache.rb +32 -5
  161. data/lib/active_record/store.rb +87 -8
  162. data/lib/active_record/table_metadata.rb +10 -17
  163. data/lib/active_record/tasks/database_tasks.rb +159 -25
  164. data/lib/active_record/tasks/mysql_database_tasks.rb +5 -5
  165. data/lib/active_record/tasks/postgresql_database_tasks.rb +5 -7
  166. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -8
  167. data/lib/active_record/test_databases.rb +38 -0
  168. data/lib/active_record/test_fixtures.rb +224 -0
  169. data/lib/active_record/timestamp.rb +39 -25
  170. data/lib/active_record/touch_later.rb +4 -2
  171. data/lib/active_record/transactions.rb +56 -65
  172. data/lib/active_record/translation.rb +1 -1
  173. data/lib/active_record/type.rb +3 -4
  174. data/lib/active_record/type/adapter_specific_registry.rb +1 -8
  175. data/lib/active_record/type_caster/connection.rb +15 -14
  176. data/lib/active_record/type_caster/map.rb +1 -4
  177. data/lib/active_record/validations/uniqueness.rb +15 -27
  178. data/lib/arel.rb +51 -0
  179. data/lib/arel/alias_predication.rb +9 -0
  180. data/lib/arel/attributes.rb +22 -0
  181. data/lib/arel/attributes/attribute.rb +37 -0
  182. data/lib/arel/collectors/bind.rb +24 -0
  183. data/lib/arel/collectors/composite.rb +31 -0
  184. data/lib/arel/collectors/plain_string.rb +20 -0
  185. data/lib/arel/collectors/sql_string.rb +20 -0
  186. data/lib/arel/collectors/substitute_binds.rb +28 -0
  187. data/lib/arel/crud.rb +42 -0
  188. data/lib/arel/delete_manager.rb +18 -0
  189. data/lib/arel/errors.rb +9 -0
  190. data/lib/arel/expressions.rb +29 -0
  191. data/lib/arel/factory_methods.rb +49 -0
  192. data/lib/arel/insert_manager.rb +49 -0
  193. data/lib/arel/math.rb +45 -0
  194. data/lib/arel/nodes.rb +68 -0
  195. data/lib/arel/nodes/and.rb +32 -0
  196. data/lib/arel/nodes/ascending.rb +23 -0
  197. data/lib/arel/nodes/binary.rb +52 -0
  198. data/lib/arel/nodes/bind_param.rb +36 -0
  199. data/lib/arel/nodes/case.rb +55 -0
  200. data/lib/arel/nodes/casted.rb +50 -0
  201. data/lib/arel/nodes/comment.rb +29 -0
  202. data/lib/arel/nodes/count.rb +12 -0
  203. data/lib/arel/nodes/delete_statement.rb +45 -0
  204. data/lib/arel/nodes/descending.rb +23 -0
  205. data/lib/arel/nodes/equality.rb +18 -0
  206. data/lib/arel/nodes/extract.rb +24 -0
  207. data/lib/arel/nodes/false.rb +16 -0
  208. data/lib/arel/nodes/full_outer_join.rb +8 -0
  209. data/lib/arel/nodes/function.rb +44 -0
  210. data/lib/arel/nodes/grouping.rb +8 -0
  211. data/lib/arel/nodes/in.rb +8 -0
  212. data/lib/arel/nodes/infix_operation.rb +80 -0
  213. data/lib/arel/nodes/inner_join.rb +8 -0
  214. data/lib/arel/nodes/insert_statement.rb +37 -0
  215. data/lib/arel/nodes/join_source.rb +20 -0
  216. data/lib/arel/nodes/matches.rb +18 -0
  217. data/lib/arel/nodes/named_function.rb +23 -0
  218. data/lib/arel/nodes/node.rb +50 -0
  219. data/lib/arel/nodes/node_expression.rb +13 -0
  220. data/lib/arel/nodes/outer_join.rb +8 -0
  221. data/lib/arel/nodes/over.rb +15 -0
  222. data/lib/arel/nodes/regexp.rb +16 -0
  223. data/lib/arel/nodes/right_outer_join.rb +8 -0
  224. data/lib/arel/nodes/select_core.rb +67 -0
  225. data/lib/arel/nodes/select_statement.rb +41 -0
  226. data/lib/arel/nodes/sql_literal.rb +16 -0
  227. data/lib/arel/nodes/string_join.rb +11 -0
  228. data/lib/arel/nodes/table_alias.rb +27 -0
  229. data/lib/arel/nodes/terminal.rb +16 -0
  230. data/lib/arel/nodes/true.rb +16 -0
  231. data/lib/arel/nodes/unary.rb +45 -0
  232. data/lib/arel/nodes/unary_operation.rb +20 -0
  233. data/lib/arel/nodes/unqualified_column.rb +22 -0
  234. data/lib/arel/nodes/update_statement.rb +41 -0
  235. data/lib/arel/nodes/values_list.rb +9 -0
  236. data/lib/arel/nodes/window.rb +126 -0
  237. data/lib/arel/nodes/with.rb +11 -0
  238. data/lib/arel/order_predications.rb +13 -0
  239. data/lib/arel/predications.rb +257 -0
  240. data/lib/arel/select_manager.rb +271 -0
  241. data/lib/arel/table.rb +110 -0
  242. data/lib/arel/tree_manager.rb +72 -0
  243. data/lib/arel/update_manager.rb +34 -0
  244. data/lib/arel/visitors.rb +20 -0
  245. data/lib/arel/visitors/depth_first.rb +204 -0
  246. data/lib/arel/visitors/dot.rb +297 -0
  247. data/lib/arel/visitors/ibm_db.rb +34 -0
  248. data/lib/arel/visitors/informix.rb +62 -0
  249. data/lib/arel/visitors/mssql.rb +157 -0
  250. data/lib/arel/visitors/mysql.rb +83 -0
  251. data/lib/arel/visitors/oracle.rb +159 -0
  252. data/lib/arel/visitors/oracle12.rb +66 -0
  253. data/lib/arel/visitors/postgresql.rb +110 -0
  254. data/lib/arel/visitors/sqlite.rb +39 -0
  255. data/lib/arel/visitors/to_sql.rb +889 -0
  256. data/lib/arel/visitors/visitor.rb +46 -0
  257. data/lib/arel/visitors/where_sql.rb +23 -0
  258. data/lib/arel/window_predications.rb +9 -0
  259. data/lib/rails/generators/active_record/migration.rb +14 -1
  260. data/lib/rails/generators/active_record/migration/migration_generator.rb +2 -5
  261. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb.tt +1 -1
  262. data/lib/rails/generators/active_record/migration/templates/migration.rb.tt +4 -2
  263. data/lib/rails/generators/active_record/model/model_generator.rb +1 -0
  264. data/lib/rails/generators/active_record/model/templates/model.rb.tt +10 -1
  265. metadata +109 -27
  266. data/lib/active_record/collection_cache_key.rb +0 -53
@@ -4,6 +4,8 @@ module ActiveRecord
4
4
  class LogSubscriber < ActiveSupport::LogSubscriber
5
5
  IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
6
6
 
7
+ class_attribute :backtrace_cleaner, default: ActiveSupport::BacktraceCleaner.new
8
+
7
9
  def self.runtime=(value)
8
10
  ActiveRecord::RuntimeRegistry.sql_runtime = value
9
11
  end
@@ -100,36 +102,15 @@ module ActiveRecord
100
102
  end
101
103
 
102
104
  def log_query_source
103
- source_line, line_number = extract_callstack(caller_locations)
104
-
105
- if source_line
106
- if defined?(::Rails.root)
107
- app_root = "#{::Rails.root.to_s}/".freeze
108
- source_line = source_line.sub(app_root, "")
109
- end
110
-
111
- logger.debug(" ↳ #{ source_line }:#{ line_number }")
112
- end
113
- end
105
+ source = extract_query_source_location(caller)
114
106
 
115
- def extract_callstack(callstack)
116
- line = callstack.find do |frame|
117
- frame.absolute_path && !ignored_callstack(frame.absolute_path)
107
+ if source
108
+ logger.debug(" ↳ #{source}")
118
109
  end
119
-
120
- offending_line = line || callstack.first
121
-
122
- [
123
- offending_line.path,
124
- offending_line.lineno
125
- ]
126
110
  end
127
111
 
128
- RAILS_GEM_ROOT = File.expand_path("../../..", __dir__) + "/"
129
-
130
- def ignored_callstack(path)
131
- path.start_with?(RAILS_GEM_ROOT) ||
132
- path.start_with?(RbConfig::CONFIG["rubylibdir"])
112
+ def extract_query_source_location(locations)
113
+ backtrace_cleaner.clean(locations.lazy).first
133
114
  end
134
115
  end
135
116
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/middleware/database_selector/resolver"
4
+
5
+ module ActiveRecord
6
+ module Middleware
7
+ # The DatabaseSelector Middleware provides a framework for automatically
8
+ # swapping from the primary to the replica database connection. Rails
9
+ # provides a basic framework to determine when to swap and allows for
10
+ # applications to write custom strategy classes to override the default
11
+ # behavior.
12
+ #
13
+ # The resolver class defines when the application should switch (i.e. read
14
+ # from the primary if a write occurred less than 2 seconds ago) and a
15
+ # resolver context class that sets a value that helps the resolver class
16
+ # decide when to switch.
17
+ #
18
+ # Rails default middleware uses the request's session to set a timestamp
19
+ # that informs the application when to read from a primary or read from a
20
+ # replica.
21
+ #
22
+ # To use the DatabaseSelector in your application with default settings add
23
+ # the following options to your environment config:
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
28
+ #
29
+ # New applications will include these lines commented out in the production.rb.
30
+ #
31
+ # The default behavior can be changed by setting the config options to a
32
+ # custom class:
33
+ #
34
+ # config.active_record.database_selector = { delay: 2.seconds }
35
+ # config.active_record.database_resolver = MyResolver
36
+ # config.active_record.database_resolver_context = MyResolver::MySession
37
+ class DatabaseSelector
38
+ def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
39
+ @app = app
40
+ @resolver_klass = resolver_klass || Resolver
41
+ @context_klass = context_klass || Resolver::Session
42
+ @options = options
43
+ end
44
+
45
+ attr_reader :resolver_klass, :context_klass, :options
46
+
47
+ # Middleware that determines which database connection to use in a multiple
48
+ # database application.
49
+ def call(env)
50
+ request = ActionDispatch::Request.new(env)
51
+
52
+ select_database(request) do
53
+ @app.call(env)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def select_database(request, &blk)
60
+ context = context_klass.call(request)
61
+ resolver = resolver_klass.call(context, options)
62
+
63
+ if reading_request?(request)
64
+ resolver.read(&blk)
65
+ else
66
+ resolver.write(&blk)
67
+ end
68
+ end
69
+
70
+ def reading_request?(request)
71
+ request.get? || request.head?
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_record/middleware/database_selector/resolver/session"
4
+
5
+ module ActiveRecord
6
+ module Middleware
7
+ class DatabaseSelector
8
+ # The Resolver class is used by the DatabaseSelector middleware to
9
+ # determine which database the request should use.
10
+ #
11
+ # To change the behavior of the Resolver class in your application,
12
+ # create a custom resolver class that inherits from
13
+ # DatabaseSelector::Resolver and implements the methods that need to
14
+ # be changed.
15
+ #
16
+ # By default the Resolver class will send read traffic to the replica
17
+ # if it's been 2 seconds since the last write.
18
+ class Resolver # :nodoc:
19
+ SEND_TO_REPLICA_DELAY = 2.seconds
20
+
21
+ def self.call(context, options = {})
22
+ new(context, options)
23
+ end
24
+
25
+ def initialize(context, options = {})
26
+ @context = context
27
+ @options = options
28
+ @delay = @options && @options[:delay] ? @options[:delay] : SEND_TO_REPLICA_DELAY
29
+ @instrumenter = ActiveSupport::Notifications.instrumenter
30
+ end
31
+
32
+ attr_reader :context, :delay, :instrumenter
33
+
34
+ def read(&blk)
35
+ if read_from_primary?
36
+ read_from_primary(&blk)
37
+ else
38
+ read_from_replica(&blk)
39
+ end
40
+ end
41
+
42
+ def write(&blk)
43
+ write_to_primary(&blk)
44
+ end
45
+
46
+ private
47
+
48
+ def read_from_primary(&blk)
49
+ ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
50
+ ActiveRecord::Base.connection_handler.while_preventing_writes do
51
+ instrumenter.instrument("database_selector.active_record.read_from_primary") do
52
+ yield
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ def read_from_replica(&blk)
59
+ ActiveRecord::Base.connected_to(role: ActiveRecord::Base.reading_role) do
60
+ instrumenter.instrument("database_selector.active_record.read_from_replica") do
61
+ yield
62
+ end
63
+ end
64
+ end
65
+
66
+ def write_to_primary(&blk)
67
+ ActiveRecord::Base.connected_to(role: ActiveRecord::Base.writing_role) do
68
+ instrumenter.instrument("database_selector.active_record.wrote_to_primary") do
69
+ yield
70
+ ensure
71
+ context.update_last_write_timestamp
72
+ end
73
+ end
74
+ end
75
+
76
+ def read_from_primary?
77
+ !time_since_last_write_ok?
78
+ end
79
+
80
+ def send_to_replica_delay
81
+ delay
82
+ end
83
+
84
+ def time_since_last_write_ok?
85
+ Time.now - context.last_write_timestamp >= send_to_replica_delay
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveRecord
4
+ module Middleware
5
+ class DatabaseSelector
6
+ class Resolver
7
+ # The session class is used by the DatabaseSelector::Resolver to save
8
+ # timestamps of the last write in the session.
9
+ #
10
+ # The last_write is used to determine whether it's safe to read
11
+ # from the replica or the request needs to be sent to the primary.
12
+ class Session # :nodoc:
13
+ def self.call(request)
14
+ new(request.session)
15
+ end
16
+
17
+ # Converts time to a timestamp that represents milliseconds since
18
+ # epoch.
19
+ def self.convert_time_to_timestamp(time)
20
+ time.to_i * 1000 + time.usec / 1000
21
+ end
22
+
23
+ # Converts milliseconds since epoch timestamp into a time object.
24
+ def self.convert_timestamp_to_time(timestamp)
25
+ timestamp ? Time.at(timestamp / 1000, (timestamp % 1000) * 1000) : Time.at(0)
26
+ end
27
+
28
+ def initialize(session)
29
+ @session = session
30
+ end
31
+
32
+ attr_reader :session
33
+
34
+ def last_write_timestamp
35
+ self.class.convert_timestamp_to_time(session[:last_write])
36
+ end
37
+
38
+ def update_last_write_timestamp
39
+ session[:last_write] = self.class.convert_time_to_timestamp(Time.now)
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "benchmark"
3
4
  require "set"
4
5
  require "zlib"
5
6
  require "active_support/core_ext/module/attribute_accessors"
7
+ require "active_support/actionable_error"
6
8
 
7
9
  module ActiveRecord
8
- class MigrationError < ActiveRecordError#:nodoc:
10
+ class MigrationError < ActiveRecordError #:nodoc:
9
11
  def initialize(message = nil)
10
12
  message = "\n\n#{message}\n\n" if message
11
13
  super
@@ -22,7 +24,7 @@ module ActiveRecord
22
24
  # t.string :zipcode
23
25
  # end
24
26
  #
25
- # execute <<-SQL
27
+ # execute <<~SQL
26
28
  # ALTER TABLE distributors
27
29
  # ADD CONSTRAINT zipchk
28
30
  # CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -40,7 +42,7 @@ module ActiveRecord
40
42
  # t.string :zipcode
41
43
  # end
42
44
  #
43
- # execute <<-SQL
45
+ # execute <<~SQL
44
46
  # ALTER TABLE distributors
45
47
  # ADD CONSTRAINT zipchk
46
48
  # CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -48,7 +50,7 @@ module ActiveRecord
48
50
  # end
49
51
  #
50
52
  # def down
51
- # execute <<-SQL
53
+ # execute <<~SQL
52
54
  # ALTER TABLE distributors
53
55
  # DROP CONSTRAINT zipchk
54
56
  # SQL
@@ -67,7 +69,7 @@ module ActiveRecord
67
69
  #
68
70
  # reversible do |dir|
69
71
  # dir.up do
70
- # execute <<-SQL
72
+ # execute <<~SQL
71
73
  # ALTER TABLE distributors
72
74
  # ADD CONSTRAINT zipchk
73
75
  # CHECK (char_length(zipcode) = 5) NO INHERIT;
@@ -75,7 +77,7 @@ module ActiveRecord
75
77
  # end
76
78
  #
77
79
  # dir.down do
78
- # execute <<-SQL
80
+ # execute <<~SQL
79
81
  # ALTER TABLE distributors
80
82
  # DROP CONSTRAINT zipchk
81
83
  # SQL
@@ -86,7 +88,7 @@ module ActiveRecord
86
88
  class IrreversibleMigration < MigrationError
87
89
  end
88
90
 
89
- class DuplicateMigrationVersionError < MigrationError#:nodoc:
91
+ class DuplicateMigrationVersionError < MigrationError #:nodoc:
90
92
  def initialize(version = nil)
91
93
  if version
92
94
  super("Multiple migrations have the version number #{version}.")
@@ -96,7 +98,7 @@ module ActiveRecord
96
98
  end
97
99
  end
98
100
 
99
- class DuplicateMigrationNameError < MigrationError#:nodoc:
101
+ class DuplicateMigrationNameError < MigrationError #:nodoc:
100
102
  def initialize(name = nil)
101
103
  if name
102
104
  super("Multiple migrations have the name #{name}.")
@@ -116,7 +118,7 @@ module ActiveRecord
116
118
  end
117
119
  end
118
120
 
119
- class IllegalMigrationNameError < MigrationError#:nodoc:
121
+ class IllegalMigrationNameError < MigrationError #:nodoc:
120
122
  def initialize(name = nil)
121
123
  if name
122
124
  super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
@@ -126,12 +128,18 @@ module ActiveRecord
126
128
  end
127
129
  end
128
130
 
129
- class PendingMigrationError < MigrationError#:nodoc:
131
+ class PendingMigrationError < MigrationError #:nodoc:
132
+ include ActiveSupport::ActionableError
133
+
134
+ action "Run pending migrations" do
135
+ ActiveRecord::Tasks::DatabaseTasks.migrate
136
+ end
137
+
130
138
  def initialize(message = nil)
131
139
  if !message && defined?(Rails.env)
132
- super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate RAILS_ENV=#{::Rails.env}")
140
+ super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate RAILS_ENV=#{::Rails.env}")
133
141
  elsif !message
134
- super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate")
142
+ super("Migrations are pending. To resolve this issue, run:\n\n rails db:migrate")
135
143
  else
136
144
  super
137
145
  end
@@ -139,8 +147,8 @@ module ActiveRecord
139
147
  end
140
148
 
141
149
  class ConcurrentMigrationError < MigrationError #:nodoc:
142
- DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running.".freeze
143
- RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock".freeze
150
+ DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running."
151
+ RELEASE_LOCK_FAILED_MESSAGE = "Failed to release advisory lock"
144
152
 
145
153
  def initialize(message = DEFAULT_MESSAGE)
146
154
  super
@@ -149,7 +157,7 @@ module ActiveRecord
149
157
 
150
158
  class NoEnvironmentInSchemaError < MigrationError #:nodoc:
151
159
  def initialize
152
- msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
160
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n rails db:environment:set"
153
161
  if defined?(Rails.env)
154
162
  super("#{msg} RAILS_ENV=#{::Rails.env}")
155
163
  else
@@ -160,7 +168,7 @@ module ActiveRecord
160
168
 
161
169
  class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
162
170
  def initialize(env = "production")
163
- msg = "You are attempting to run a destructive action against your '#{env}' database.\n".dup
171
+ msg = +"You are attempting to run a destructive action against your '#{env}' database.\n"
164
172
  msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
165
173
  msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
166
174
  super(msg)
@@ -169,10 +177,10 @@ module ActiveRecord
169
177
 
170
178
  class EnvironmentMismatchError < ActiveRecordError
171
179
  def initialize(current: nil, stored: nil)
172
- msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n".dup
180
+ msg = +"You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
173
181
  msg << "You are running in `#{ current }` environment. "
174
182
  msg << "If you are sure you want to continue, first set the environment using:\n\n"
175
- msg << " bin/rails db:environment:set"
183
+ msg << " rails db:environment:set"
176
184
  if defined?(Rails.env)
177
185
  super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
178
186
  else
@@ -307,7 +315,7 @@ module ActiveRecord
307
315
  # named +column_name+ from the table called +table_name+.
308
316
  # * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
309
317
  # columns from the table definition.
310
- # * <tt>remove_foreign_key(from_table, options_or_to_table)</tt>: Removes the
318
+ # * <tt>remove_foreign_key(from_table, to_table = nil, **options)</tt>: Removes the
311
319
  # given foreign key from the table called +table_name+.
312
320
  # * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
313
321
  # specified by +column_names+.
@@ -351,7 +359,7 @@ module ActiveRecord
351
359
  # <tt>rails db:migrate</tt>. This will update the database by running all of the
352
360
  # pending migrations, creating the <tt>schema_migrations</tt> table
353
361
  # (see "About the schema_migrations table" section below) if missing. It will also
354
- # invoke the db:schema:dump task, which will update your db/schema.rb file
362
+ # invoke the db:schema:dump command, which will update your db/schema.rb file
355
363
  # to match the structure of your database.
356
364
  #
357
365
  # To roll the database back to a previous migration version, use
@@ -486,9 +494,9 @@ module ActiveRecord
486
494
  # This migration will create the horses table for you on the way up, and
487
495
  # automatically figure out how to drop the table on the way down.
488
496
  #
489
- # Some commands like +remove_column+ cannot be reversed. If you care to
490
- # define how to move up and down in these cases, you should define the +up+
491
- # and +down+ methods as before.
497
+ # Some commands cannot be reversed. If you care to define how to move up
498
+ # and down in these cases, you should define the +up+ and +down+ methods
499
+ # as before.
492
500
  #
493
501
  # If a command cannot be reversed, an
494
502
  # <tt>ActiveRecord::IrreversibleMigration</tt> exception will be raised when
@@ -519,10 +527,10 @@ module ActiveRecord
519
527
  autoload :Compatibility, "active_record/migration/compatibility"
520
528
 
521
529
  # This must be defined before the inherited hook, below
522
- class Current < Migration # :nodoc:
530
+ class Current < Migration #:nodoc:
523
531
  end
524
532
 
525
- def self.inherited(subclass) # :nodoc:
533
+ def self.inherited(subclass) #:nodoc:
526
534
  super
527
535
  if subclass.superclass == Migration
528
536
  raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
@@ -540,7 +548,7 @@ module ActiveRecord
540
548
  ActiveRecord::VERSION::STRING.to_f
541
549
  end
542
550
 
543
- MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
551
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ #:nodoc:
544
552
 
545
553
  # This class is used to verify that all migrations have been run before
546
554
  # loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
@@ -567,10 +575,10 @@ module ActiveRecord
567
575
  end
568
576
 
569
577
  class << self
570
- attr_accessor :delegate # :nodoc:
571
- attr_accessor :disable_ddl_transaction # :nodoc:
578
+ attr_accessor :delegate #:nodoc:
579
+ attr_accessor :disable_ddl_transaction #:nodoc:
572
580
 
573
- def nearest_delegate # :nodoc:
581
+ def nearest_delegate #:nodoc:
574
582
  delegate || superclass.nearest_delegate
575
583
  end
576
584
 
@@ -594,13 +602,13 @@ module ActiveRecord
594
602
  end
595
603
  end
596
604
 
597
- def maintain_test_schema! # :nodoc:
605
+ def maintain_test_schema! #:nodoc:
598
606
  if ActiveRecord::Base.maintain_test_schema
599
607
  suppress_messages { load_schema_if_pending! }
600
608
  end
601
609
  end
602
610
 
603
- def method_missing(name, *args, &block) # :nodoc:
611
+ def method_missing(name, *args, &block) #:nodoc:
604
612
  nearest_delegate.send(name, *args, &block)
605
613
  end
606
614
 
@@ -617,7 +625,7 @@ module ActiveRecord
617
625
  end
618
626
  end
619
627
 
620
- def disable_ddl_transaction # :nodoc:
628
+ def disable_ddl_transaction #:nodoc:
621
629
  self.class.disable_ddl_transaction
622
630
  end
623
631
 
@@ -677,15 +685,13 @@ module ActiveRecord
677
685
  if connection.respond_to? :revert
678
686
  connection.revert { yield }
679
687
  else
680
- recorder = CommandRecorder.new(connection)
688
+ recorder = command_recorder
681
689
  @connection = recorder
682
690
  suppress_messages do
683
691
  connection.revert { yield }
684
692
  end
685
693
  @connection = recorder.delegate
686
- recorder.commands.each do |cmd, args, block|
687
- send(cmd, *args, &block)
688
- end
694
+ recorder.replay(self)
689
695
  end
690
696
  end
691
697
  end
@@ -694,7 +700,7 @@ module ActiveRecord
694
700
  connection.respond_to?(:reverting) && connection.reverting
695
701
  end
696
702
 
697
- ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
703
+ ReversibleBlockHelper = Struct.new(:reverting) do #:nodoc:
698
704
  def up
699
705
  yield unless reverting
700
706
  end
@@ -830,10 +836,14 @@ module ActiveRecord
830
836
  write "== %s %s" % [text, "=" * length]
831
837
  end
832
838
 
839
+ # Takes a message argument and outputs it as is.
840
+ # A second boolean argument can be passed to specify whether to indent or not.
833
841
  def say(message, subitem = false)
834
842
  write "#{subitem ? " ->" : "--"} #{message}"
835
843
  end
836
844
 
845
+ # Outputs text along with how long it took to run its block.
846
+ # If the block returns an integer it assumes it is the number of rows affected.
837
847
  def say_with_time(message)
838
848
  say(message)
839
849
  result = nil
@@ -843,6 +853,7 @@ module ActiveRecord
843
853
  result
844
854
  end
845
855
 
856
+ # Takes a block as an argument and suppresses any output generated by the block.
846
857
  def suppress_messages
847
858
  save, self.verbose = verbose, false
848
859
  yield
@@ -874,18 +885,19 @@ module ActiveRecord
874
885
 
875
886
  def copy(destination, sources, options = {})
876
887
  copied = []
888
+ schema_migration = options[:schema_migration] || ActiveRecord::SchemaMigration
877
889
 
878
890
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
879
891
 
880
- destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
892
+ destination_migrations = ActiveRecord::MigrationContext.new(destination, schema_migration).migrations
881
893
  last = destination_migrations.last
882
894
  sources.each do |scope, path|
883
- source_migrations = ActiveRecord::MigrationContext.new(path).migrations
895
+ source_migrations = ActiveRecord::MigrationContext.new(path, schema_migration).migrations
884
896
 
885
897
  source_migrations.each do |migration|
886
898
  source = File.binread(migration.filename)
887
899
  inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
888
- magic_comments = "".dup
900
+ magic_comments = +""
889
901
  loop do
890
902
  # If we have a magic comment in the original migration,
891
903
  # insert our comment after the first newline(end of the magic comment line)
@@ -956,6 +968,10 @@ module ActiveRecord
956
968
  yield
957
969
  end
958
970
  end
971
+
972
+ def command_recorder
973
+ CommandRecorder.new(connection)
974
+ end
959
975
  end
960
976
 
961
977
  # MigrationProxy is used to defer loading of the actual migration classes
@@ -998,11 +1014,12 @@ module ActiveRecord
998
1014
  end
999
1015
  end
1000
1016
 
1001
- class MigrationContext # :nodoc:
1002
- attr_reader :migrations_paths
1017
+ class MigrationContext #:nodoc:
1018
+ attr_reader :migrations_paths, :schema_migration
1003
1019
 
1004
- def initialize(migrations_paths)
1020
+ def initialize(migrations_paths, schema_migration)
1005
1021
  @migrations_paths = migrations_paths
1022
+ @schema_migration = schema_migration
1006
1023
  end
1007
1024
 
1008
1025
  def migrate(target_version = nil, &block)
@@ -1033,7 +1050,7 @@ module ActiveRecord
1033
1050
  migrations
1034
1051
  end
1035
1052
 
1036
- Migrator.new(:up, selected_migrations, target_version).migrate
1053
+ Migrator.new(:up, selected_migrations, schema_migration, target_version).migrate
1037
1054
  end
1038
1055
 
1039
1056
  def down(target_version = nil)
@@ -1043,20 +1060,20 @@ module ActiveRecord
1043
1060
  migrations
1044
1061
  end
1045
1062
 
1046
- Migrator.new(:down, selected_migrations, target_version).migrate
1063
+ Migrator.new(:down, selected_migrations, schema_migration, target_version).migrate
1047
1064
  end
1048
1065
 
1049
1066
  def run(direction, target_version)
1050
- Migrator.new(direction, migrations, target_version).run
1067
+ Migrator.new(direction, migrations, schema_migration, target_version).run
1051
1068
  end
1052
1069
 
1053
1070
  def open
1054
- Migrator.new(:up, migrations, nil)
1071
+ Migrator.new(:up, migrations, schema_migration)
1055
1072
  end
1056
1073
 
1057
1074
  def get_all_versions
1058
- if SchemaMigration.table_exists?
1059
- SchemaMigration.all_versions.map(&:to_i)
1075
+ if schema_migration.table_exists?
1076
+ schema_migration.all_versions.map(&:to_i)
1060
1077
  else
1061
1078
  []
1062
1079
  end
@@ -1079,10 +1096,6 @@ module ActiveRecord
1079
1096
  migrations.last || NullMigration.new
1080
1097
  end
1081
1098
 
1082
- def parse_migration_filename(filename) # :nodoc:
1083
- File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1084
- end
1085
-
1086
1099
  def migrations
1087
1100
  migrations = migration_files.map do |file|
1088
1101
  version, name, scope = parse_migration_filename(file)
@@ -1097,12 +1110,12 @@ module ActiveRecord
1097
1110
  end
1098
1111
 
1099
1112
  def migrations_status
1100
- db_list = ActiveRecord::SchemaMigration.normalized_versions
1113
+ db_list = schema_migration.normalized_versions
1101
1114
 
1102
1115
  file_list = migration_files.map do |file|
1103
1116
  version, name, scope = parse_migration_filename(file)
1104
1117
  raise IllegalMigrationNameError.new(file) unless version
1105
- version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
1118
+ version = schema_migration.normalize_migration_number(version)
1106
1119
  status = db_list.delete(version) ? "up" : "down"
1107
1120
  [status, version, (name + scope).humanize]
1108
1121
  end.compact
@@ -1114,11 +1127,6 @@ module ActiveRecord
1114
1127
  (db_list + file_list).sort_by { |_, version, _| version }
1115
1128
  end
1116
1129
 
1117
- def migration_files
1118
- paths = Array(migrations_paths)
1119
- Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1120
- end
1121
-
1122
1130
  def current_environment
1123
1131
  ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1124
1132
  end
@@ -1137,8 +1145,17 @@ module ActiveRecord
1137
1145
  end
1138
1146
 
1139
1147
  private
1148
+ def migration_files
1149
+ paths = Array(migrations_paths)
1150
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1151
+ end
1152
+
1153
+ def parse_migration_filename(filename)
1154
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1155
+ end
1156
+
1140
1157
  def move(direction, steps)
1141
- migrator = Migrator.new(direction, migrations)
1158
+ migrator = Migrator.new(direction, migrations, schema_migration)
1142
1159
 
1143
1160
  if current_version != 0 && !migrator.current_migration
1144
1161
  raise UnknownMigrationVersionError.new(current_version)
@@ -1161,30 +1178,24 @@ module ActiveRecord
1161
1178
  class << self
1162
1179
  attr_accessor :migrations_paths
1163
1180
 
1164
- def migrations_path=(path)
1165
- ActiveSupport::Deprecation.warn \
1166
- "`ActiveRecord::Migrator.migrations_path=` is now deprecated and will be removed in Rails 6.0. " \
1167
- "You can set the `migrations_paths` on the `connection` instead through the `database.yml`."
1168
- self.migrations_paths = [path]
1169
- end
1170
-
1171
1181
  # For cases where a table doesn't exist like loading from schema cache
1172
1182
  def current_version
1173
- MigrationContext.new(migrations_paths).current_version
1183
+ MigrationContext.new(migrations_paths, SchemaMigration).current_version
1174
1184
  end
1175
1185
  end
1176
1186
 
1177
1187
  self.migrations_paths = ["db/migrate"]
1178
1188
 
1179
- def initialize(direction, migrations, target_version = nil)
1189
+ def initialize(direction, migrations, schema_migration, target_version = nil)
1180
1190
  @direction = direction
1181
1191
  @target_version = target_version
1182
1192
  @migrated_versions = nil
1183
1193
  @migrations = migrations
1194
+ @schema_migration = schema_migration
1184
1195
 
1185
1196
  validate(@migrations)
1186
1197
 
1187
- ActiveRecord::SchemaMigration.create_table
1198
+ @schema_migration.create_table
1188
1199
  ActiveRecord::InternalMetadata.create_table
1189
1200
  end
1190
1201
 
@@ -1238,7 +1249,7 @@ module ActiveRecord
1238
1249
  end
1239
1250
 
1240
1251
  def load_migrated
1241
- @migrated_versions = Set.new(Base.connection.migration_context.get_all_versions)
1252
+ @migrated_versions = Set.new(@schema_migration.all_versions.map(&:to_i))
1242
1253
  end
1243
1254
 
1244
1255
  private
@@ -1293,7 +1304,7 @@ module ActiveRecord
1293
1304
  record_version_state_after_migrating(migration.version)
1294
1305
  end
1295
1306
  rescue => e
1296
- msg = "An error has occurred, ".dup
1307
+ msg = +"An error has occurred, "
1297
1308
  msg << "this and " if use_transaction?(migration)
1298
1309
  msg << "all later migrations canceled:\n\n#{e}"
1299
1310
  raise StandardError, msg, e.backtrace
@@ -1322,10 +1333,10 @@ module ActiveRecord
1322
1333
  def record_version_state_after_migrating(version)
1323
1334
  if down?
1324
1335
  migrated.delete(version)
1325
- ActiveRecord::SchemaMigration.where(version: version.to_s).delete_all
1336
+ @schema_migration.delete_by(version: version.to_s)
1326
1337
  else
1327
1338
  migrated << version
1328
- ActiveRecord::SchemaMigration.create!(version: version.to_s)
1339
+ @schema_migration.create!(version: version.to_s)
1329
1340
  end
1330
1341
  end
1331
1342
 
@@ -1351,7 +1362,7 @@ module ActiveRecord
1351
1362
  end
1352
1363
 
1353
1364
  def use_advisory_lock?
1354
- Base.connection.supports_advisory_locks?
1365
+ Base.connection.advisory_locks_enabled?
1355
1366
  end
1356
1367
 
1357
1368
  def with_advisory_lock