activerecord 5.1.7 → 5.2.4.3

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 (261) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +556 -685
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -5
  5. data/examples/performance.rb +2 -0
  6. data/examples/simple.rb +2 -0
  7. data/lib/active_record.rb +11 -4
  8. data/lib/active_record/aggregations.rb +6 -5
  9. data/lib/active_record/association_relation.rb +7 -5
  10. data/lib/active_record/associations.rb +40 -63
  11. data/lib/active_record/associations/alias_tracker.rb +19 -27
  12. data/lib/active_record/associations/association.rb +41 -37
  13. data/lib/active_record/associations/association_scope.rb +38 -50
  14. data/lib/active_record/associations/belongs_to_association.rb +27 -8
  15. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  16. data/lib/active_record/associations/builder/association.rb +4 -7
  17. data/lib/active_record/associations/builder/belongs_to.rb +12 -4
  18. data/lib/active_record/associations/builder/collection_association.rb +3 -3
  19. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +3 -1
  20. data/lib/active_record/associations/builder/has_many.rb +2 -0
  21. data/lib/active_record/associations/builder/has_one.rb +2 -0
  22. data/lib/active_record/associations/builder/singular_association.rb +2 -0
  23. data/lib/active_record/associations/collection_association.rb +59 -47
  24. data/lib/active_record/associations/collection_proxy.rb +20 -49
  25. data/lib/active_record/associations/foreign_association.rb +2 -0
  26. data/lib/active_record/associations/has_many_association.rb +12 -1
  27. data/lib/active_record/associations/has_many_through_association.rb +36 -30
  28. data/lib/active_record/associations/has_one_association.rb +12 -1
  29. data/lib/active_record/associations/has_one_through_association.rb +13 -8
  30. data/lib/active_record/associations/join_dependency.rb +48 -93
  31. data/lib/active_record/associations/join_dependency/join_association.rb +39 -63
  32. data/lib/active_record/associations/join_dependency/join_base.rb +9 -8
  33. data/lib/active_record/associations/join_dependency/join_part.rb +9 -9
  34. data/lib/active_record/associations/preloader.rb +18 -38
  35. data/lib/active_record/associations/preloader/association.rb +45 -61
  36. data/lib/active_record/associations/preloader/through_association.rb +71 -79
  37. data/lib/active_record/associations/singular_association.rb +14 -16
  38. data/lib/active_record/associations/through_association.rb +26 -11
  39. data/lib/active_record/attribute_assignment.rb +2 -5
  40. data/lib/active_record/attribute_decorators.rb +3 -2
  41. data/lib/active_record/attribute_methods.rb +65 -24
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +2 -0
  43. data/lib/active_record/attribute_methods/dirty.rb +30 -214
  44. data/lib/active_record/attribute_methods/primary_key.rb +7 -6
  45. data/lib/active_record/attribute_methods/query.rb +2 -0
  46. data/lib/active_record/attribute_methods/read.rb +9 -3
  47. data/lib/active_record/attribute_methods/serialization.rb +23 -0
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +6 -8
  49. data/lib/active_record/attribute_methods/write.rb +21 -9
  50. data/lib/active_record/attributes.rb +6 -5
  51. data/lib/active_record/autosave_association.rb +35 -19
  52. data/lib/active_record/base.rb +2 -0
  53. data/lib/active_record/callbacks.rb +8 -6
  54. data/lib/active_record/coders/json.rb +2 -0
  55. data/lib/active_record/coders/yaml_column.rb +2 -0
  56. data/lib/active_record/collection_cache_key.rb +12 -8
  57. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +139 -41
  58. data/lib/active_record/connection_adapters/abstract/database_limits.rb +7 -0
  59. data/lib/active_record/connection_adapters/abstract/database_statements.rb +174 -33
  60. data/lib/active_record/connection_adapters/abstract/query_cache.rb +15 -5
  61. data/lib/active_record/connection_adapters/abstract/quoting.rb +13 -31
  62. data/lib/active_record/connection_adapters/abstract/savepoints.rb +2 -0
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +14 -5
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +64 -6
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +31 -53
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +152 -81
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +66 -21
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +84 -97
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +92 -165
  70. data/lib/active_record/connection_adapters/column.rb +3 -1
  71. data/lib/active_record/connection_adapters/connection_specification.rb +17 -3
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +13 -2
  73. data/lib/active_record/connection_adapters/mysql/column.rb +2 -0
  74. data/lib/active_record/connection_adapters/mysql/database_statements.rb +47 -2
  75. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +2 -0
  76. data/lib/active_record/connection_adapters/mysql/quoting.rb +9 -10
  77. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +5 -3
  78. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +7 -10
  79. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +30 -30
  80. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +106 -1
  81. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +2 -0
  82. data/lib/active_record/connection_adapters/mysql2_adapter.rb +8 -2
  83. data/lib/active_record/connection_adapters/postgresql/column.rb +2 -0
  84. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +6 -0
  85. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +2 -0
  86. data/lib/active_record/connection_adapters/postgresql/oid.rb +3 -1
  87. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -0
  89. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  90. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +2 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +2 -0
  92. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +23 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +2 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +2 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +2 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -1
  99. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +2 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +3 -1
  101. data/lib/active_record/connection_adapters/postgresql/oid/oid.rb +2 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +2 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -2
  104. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +2 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +4 -2
  106. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +2 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +2 -0
  109. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -0
  110. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +19 -25
  111. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +50 -0
  112. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +24 -11
  113. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +20 -13
  114. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +233 -111
  115. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +2 -0
  116. data/lib/active_record/connection_adapters/postgresql/utils.rb +3 -1
  117. data/lib/active_record/connection_adapters/postgresql_adapter.rb +57 -73
  118. data/lib/active_record/connection_adapters/schema_cache.rb +4 -2
  119. data/lib/active_record/connection_adapters/sql_type_metadata.rb +2 -0
  120. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +2 -0
  121. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +22 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +2 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +6 -15
  124. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +3 -2
  125. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +75 -1
  126. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +81 -94
  127. data/lib/active_record/connection_adapters/statement_pool.rb +2 -0
  128. data/lib/active_record/connection_handling.rb +4 -2
  129. data/lib/active_record/core.rb +41 -61
  130. data/lib/active_record/counter_cache.rb +10 -3
  131. data/lib/active_record/define_callbacks.rb +5 -3
  132. data/lib/active_record/dynamic_matchers.rb +9 -9
  133. data/lib/active_record/enum.rb +18 -13
  134. data/lib/active_record/errors.rb +42 -3
  135. data/lib/active_record/explain.rb +3 -1
  136. data/lib/active_record/explain_registry.rb +2 -0
  137. data/lib/active_record/explain_subscriber.rb +2 -0
  138. data/lib/active_record/fixture_set/file.rb +2 -0
  139. data/lib/active_record/fixtures.rb +67 -60
  140. data/lib/active_record/gem_version.rb +5 -3
  141. data/lib/active_record/inheritance.rb +49 -19
  142. data/lib/active_record/integration.rb +58 -19
  143. data/lib/active_record/internal_metadata.rb +2 -0
  144. data/lib/active_record/legacy_yaml_adapter.rb +3 -1
  145. data/lib/active_record/locking/optimistic.rb +14 -17
  146. data/lib/active_record/locking/pessimistic.rb +9 -6
  147. data/lib/active_record/log_subscriber.rb +43 -0
  148. data/lib/active_record/migration.rb +189 -139
  149. data/lib/active_record/migration/command_recorder.rb +11 -9
  150. data/lib/active_record/migration/compatibility.rb +47 -9
  151. data/lib/active_record/migration/join_table.rb +2 -0
  152. data/lib/active_record/model_schema.rb +16 -21
  153. data/lib/active_record/nested_attributes.rb +18 -6
  154. data/lib/active_record/no_touching.rb +3 -1
  155. data/lib/active_record/null_relation.rb +2 -0
  156. data/lib/active_record/persistence.rb +167 -16
  157. data/lib/active_record/query_cache.rb +6 -8
  158. data/lib/active_record/querying.rb +4 -2
  159. data/lib/active_record/railtie.rb +62 -6
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +2 -0
  162. data/lib/active_record/railties/databases.rake +46 -36
  163. data/lib/active_record/readonly_attributes.rb +3 -2
  164. data/lib/active_record/reflection.rb +108 -194
  165. data/lib/active_record/relation.rb +120 -214
  166. data/lib/active_record/relation/batches.rb +20 -5
  167. data/lib/active_record/relation/batches/batch_enumerator.rb +2 -0
  168. data/lib/active_record/relation/calculations.rb +45 -19
  169. data/lib/active_record/relation/delegation.rb +45 -27
  170. data/lib/active_record/relation/finder_methods.rb +75 -76
  171. data/lib/active_record/relation/from_clause.rb +2 -8
  172. data/lib/active_record/relation/merger.rb +53 -23
  173. data/lib/active_record/relation/predicate_builder.rb +60 -79
  174. data/lib/active_record/relation/predicate_builder/array_handler.rb +10 -7
  175. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  176. data/lib/active_record/relation/predicate_builder/base_handler.rb +2 -2
  177. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +12 -1
  178. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  179. data/lib/active_record/relation/predicate_builder/range_handler.rb +26 -9
  180. data/lib/active_record/relation/predicate_builder/relation_handler.rb +6 -0
  181. data/lib/active_record/relation/query_attribute.rb +28 -2
  182. data/lib/active_record/relation/query_methods.rb +128 -99
  183. data/lib/active_record/relation/record_fetch_warning.rb +2 -0
  184. data/lib/active_record/relation/spawn_methods.rb +4 -2
  185. data/lib/active_record/relation/where_clause.rb +65 -68
  186. data/lib/active_record/relation/where_clause_factory.rb +5 -48
  187. data/lib/active_record/result.rb +2 -0
  188. data/lib/active_record/runtime_registry.rb +2 -0
  189. data/lib/active_record/sanitization.rb +129 -121
  190. data/lib/active_record/schema.rb +4 -2
  191. data/lib/active_record/schema_dumper.rb +36 -26
  192. data/lib/active_record/schema_migration.rb +2 -0
  193. data/lib/active_record/scoping.rb +9 -8
  194. data/lib/active_record/scoping/default.rb +8 -9
  195. data/lib/active_record/scoping/named.rb +23 -7
  196. data/lib/active_record/secure_token.rb +2 -0
  197. data/lib/active_record/serialization.rb +2 -0
  198. data/lib/active_record/statement_cache.rb +23 -13
  199. data/lib/active_record/store.rb +3 -1
  200. data/lib/active_record/suppressor.rb +2 -0
  201. data/lib/active_record/table_metadata.rb +12 -3
  202. data/lib/active_record/tasks/database_tasks.rb +25 -14
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +9 -48
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +10 -2
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +25 -3
  206. data/lib/active_record/timestamp.rb +6 -6
  207. data/lib/active_record/touch_later.rb +2 -0
  208. data/lib/active_record/transactions.rb +33 -28
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type.rb +4 -1
  211. data/lib/active_record/type/adapter_specific_registry.rb +2 -0
  212. data/lib/active_record/type/date.rb +2 -0
  213. data/lib/active_record/type/date_time.rb +2 -0
  214. data/lib/active_record/type/decimal_without_scale.rb +2 -0
  215. data/lib/active_record/type/hash_lookup_type_map.rb +2 -0
  216. data/lib/active_record/type/internal/timezone.rb +2 -0
  217. data/lib/active_record/type/json.rb +30 -0
  218. data/lib/active_record/type/serialized.rb +2 -0
  219. data/lib/active_record/type/text.rb +2 -0
  220. data/lib/active_record/type/time.rb +2 -0
  221. data/lib/active_record/type/type_map.rb +2 -0
  222. data/lib/active_record/type/unsigned_integer.rb +2 -0
  223. data/lib/active_record/type_caster.rb +2 -0
  224. data/lib/active_record/type_caster/connection.rb +2 -0
  225. data/lib/active_record/type_caster/map.rb +3 -1
  226. data/lib/active_record/validations.rb +2 -0
  227. data/lib/active_record/validations/absence.rb +2 -0
  228. data/lib/active_record/validations/associated.rb +2 -0
  229. data/lib/active_record/validations/length.rb +2 -0
  230. data/lib/active_record/validations/presence.rb +2 -0
  231. data/lib/active_record/validations/uniqueness.rb +35 -5
  232. data/lib/active_record/version.rb +2 -0
  233. data/lib/rails/generators/active_record.rb +3 -1
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/{model/templates/application_record.rb → application_record/templates/application_record.rb.tt} +0 -0
  236. data/lib/rails/generators/active_record/migration.rb +2 -0
  237. data/lib/rails/generators/active_record/migration/migration_generator.rb +3 -1
  238. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +0 -0
  239. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +0 -0
  240. data/lib/rails/generators/active_record/model/model_generator.rb +2 -23
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +0 -0
  242. data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
  243. metadata +23 -36
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -15
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -17
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -15
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -15
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -18
  251. data/lib/active_record/attribute.rb +0 -240
  252. data/lib/active_record/attribute/user_provided_default.rb +0 -30
  253. data/lib/active_record/attribute_mutation_tracker.rb +0 -122
  254. data/lib/active_record/attribute_set.rb +0 -113
  255. data/lib/active_record/attribute_set/builder.rb +0 -126
  256. data/lib/active_record/attribute_set/yaml_encoder.rb +0 -41
  257. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -10
  258. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  259. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +0 -88
  260. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +0 -59
  261. data/lib/active_record/type/internal/abstract_json.rb +0 -37
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  # Returns the version of the currently loaded Active Record as a <tt>Gem::Version</tt>
3
5
  def self.gem_version
@@ -6,9 +8,9 @@ module ActiveRecord
6
8
 
7
9
  module VERSION
8
10
  MAJOR = 5
9
- MINOR = 1
10
- TINY = 7
11
- PRE = nil
11
+ MINOR = 2
12
+ TINY = 4
13
+ PRE = "3"
12
14
 
13
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
16
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/hash/indifferent_access"
2
4
 
3
5
  module ActiveRecord
@@ -30,7 +32,7 @@ module ActiveRecord
30
32
  # for differentiating between them or reloading the right type with find.
31
33
  #
32
34
  # Note, all the attributes for all the cases are kept in the same table. Read more:
33
- # http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
35
+ # https://www.martinfowler.com/eaaCatalog/singleTableInheritance.html
34
36
  #
35
37
  module Inheritance
36
38
  extend ActiveSupport::Concern
@@ -38,22 +40,20 @@ module ActiveRecord
38
40
  included do
39
41
  # Determines whether to store the full constant name including namespace when using STI.
40
42
  # This is true, by default.
41
- class_attribute :store_full_sti_class, instance_writer: false
42
- self.store_full_sti_class = true
43
+ class_attribute :store_full_sti_class, instance_writer: false, default: true
43
44
  end
44
45
 
45
46
  module ClassMethods
46
47
  # Determines if one of the attributes passed in is the inheritance column,
47
48
  # and if the inheritance column is attr accessible, it initializes an
48
49
  # instance of the given subclass instead of the base class.
49
- def new(*args, &block)
50
+ def new(attributes = nil, &block)
50
51
  if abstract_class? || self == Base
51
52
  raise NotImplementedError, "#{self} is an abstract class and cannot be instantiated."
52
53
  end
53
54
 
54
- attrs = args.first
55
55
  if has_attribute?(inheritance_column)
56
- subclass = subclass_from_attributes(attrs)
56
+ subclass = subclass_from_attributes(attributes)
57
57
 
58
58
  if subclass.nil? && base_class == self
59
59
  subclass = subclass_from_attributes(column_defaults)
@@ -61,7 +61,7 @@ module ActiveRecord
61
61
  end
62
62
 
63
63
  if subclass && subclass != self
64
- subclass.new(*args, &block)
64
+ subclass.new(attributes, &block)
65
65
  else
66
66
  super
67
67
  end
@@ -104,21 +104,47 @@ module ActiveRecord
104
104
  end
105
105
  end
106
106
 
107
- # Set this to true if this is an abstract class (see <tt>abstract_class?</tt>).
108
- # If you are using inheritance with ActiveRecord and don't want child classes
109
- # to utilize the implied STI table name of the parent class, this will need to be true.
110
- # For example, given the following:
107
+ # Set this to +true+ if this is an abstract class (see
108
+ # <tt>abstract_class?</tt>).
109
+ # If you are using inheritance with Active Record and don't want a class
110
+ # to be considered as part of the STI hierarchy, you must set this to
111
+ # true.
112
+ # +ApplicationRecord+, for example, is generated as an abstract class.
113
+ #
114
+ # Consider the following default behaviour:
115
+ #
116
+ # Shape = Class.new(ActiveRecord::Base)
117
+ # Polygon = Class.new(Shape)
118
+ # Square = Class.new(Polygon)
119
+ #
120
+ # Shape.table_name # => "shapes"
121
+ # Polygon.table_name # => "shapes"
122
+ # Square.table_name # => "shapes"
123
+ # Shape.create! # => #<Shape id: 1, type: nil>
124
+ # Polygon.create! # => #<Polygon id: 2, type: "Polygon">
125
+ # Square.create! # => #<Square id: 3, type: "Square">
126
+ #
127
+ # However, when using <tt>abstract_class</tt>, +Shape+ is omitted from
128
+ # the hierarchy:
111
129
  #
112
- # class SuperClass < ActiveRecord::Base
130
+ # class Shape < ActiveRecord::Base
113
131
  # self.abstract_class = true
114
132
  # end
115
- # class Child < SuperClass
116
- # self.table_name = 'the_table_i_really_want'
117
- # end
118
- #
133
+ # Polygon = Class.new(Shape)
134
+ # Square = Class.new(Polygon)
119
135
  #
120
- # <tt>self.abstract_class = true</tt> is required to make <tt>Child<.find,.create, or any Arel method></tt> use <tt>the_table_i_really_want</tt> instead of a table called <tt>super_classes</tt>
136
+ # Shape.table_name # => nil
137
+ # Polygon.table_name # => "polygons"
138
+ # Square.table_name # => "polygons"
139
+ # Shape.create! # => NotImplementedError: Shape is an abstract class and cannot be instantiated.
140
+ # Polygon.create! # => #<Polygon id: 1, type: nil>
141
+ # Square.create! # => #<Square id: 2, type: "Square">
121
142
  #
143
+ # Note that in the above example, to disallow the creation of a plain
144
+ # +Polygon+, you should use <tt>validates :type, presence: true</tt>,
145
+ # instead of setting it as an abstract class. This way, +Polygon+ will
146
+ # stay in the hierarchy, and Active Record will continue to correctly
147
+ # derive the table name.
122
148
  attr_accessor :abstract_class
123
149
 
124
150
  # Returns whether this class is an abstract class or not.
@@ -130,6 +156,10 @@ module ActiveRecord
130
156
  store_full_sti_class ? name : name.demodulize
131
157
  end
132
158
 
159
+ def polymorphic_name
160
+ base_class.name
161
+ end
162
+
133
163
  def inherited(subclass)
134
164
  subclass.instance_variable_set(:@_type_candidates_cache, Concurrent::Map.new)
135
165
  super
@@ -217,7 +247,7 @@ module ActiveRecord
217
247
  def subclass_from_attributes(attrs)
218
248
  attrs = attrs.to_h if attrs.respond_to?(:permitted?)
219
249
  if attrs.is_a?(Hash)
220
- subclass_name = attrs.with_indifferent_access[inheritance_column]
250
+ subclass_name = attrs[inheritance_column] || attrs[inheritance_column.to_sym]
221
251
 
222
252
  if subclass_name.present?
223
253
  find_sti_class(subclass_name)
@@ -246,7 +276,7 @@ module ActiveRecord
246
276
  def ensure_proper_type
247
277
  klass = self.class
248
278
  if klass.finder_needs_type_condition?
249
- write_attribute(klass.inheritance_column, klass.sti_name)
279
+ _write_attribute(klass.inheritance_column, klass.sti_name)
250
280
  end
251
281
  end
252
282
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/string/filters"
2
4
 
3
5
  module ActiveRecord
@@ -7,12 +9,19 @@ module ActiveRecord
7
9
  included do
8
10
  ##
9
11
  # :singleton-method:
10
- # Indicates the format used to generate the timestamp in the cache key.
11
- # Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
12
+ # Indicates the format used to generate the timestamp in the cache key, if
13
+ # versioning is off. Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
12
14
  #
13
15
  # This is +:usec+, by default.
14
- class_attribute :cache_timestamp_format, instance_writer: false
15
- self.cache_timestamp_format = :usec
16
+ class_attribute :cache_timestamp_format, instance_writer: false, default: :usec
17
+
18
+ ##
19
+ # :singleton-method:
20
+ # Indicates whether to use a stable #cache_key method that is accompanied
21
+ # by a changing version in the #cache_version method.
22
+ #
23
+ # This is +false+, by default until Rails 6.0.
24
+ class_attribute :cache_versioning, instance_writer: false, default: false
16
25
  end
17
26
 
18
27
  # Returns a +String+, which Action Pack uses for constructing a URL to this
@@ -42,35 +51,65 @@ module ActiveRecord
42
51
  id && id.to_s # Be sure to stringify the id for routes
43
52
  end
44
53
 
45
- # Returns a cache key that can be used to identify this record.
54
+ # Returns a stable cache key that can be used to identify this record.
46
55
  #
47
56
  # Product.new.cache_key # => "products/new"
48
- # Product.find(5).cache_key # => "products/5" (updated_at not available)
49
- # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
57
+ # Product.find(5).cache_key # => "products/5"
50
58
  #
51
- # You can also pass a list of named timestamps, and the newest in the list will be
52
- # used to generate the key:
59
+ # If ActiveRecord::Base.cache_versioning is turned off, as it was in Rails 5.1 and earlier,
60
+ # the cache key will also include a version.
53
61
  #
54
- # Person.find(5).cache_key(:updated_at, :last_reviewed_at)
62
+ # Product.cache_versioning = false
63
+ # Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
55
64
  def cache_key(*timestamp_names)
56
65
  if new_record?
57
66
  "#{model_name.cache_key}/new"
58
67
  else
59
- timestamp = if timestamp_names.any?
60
- max_updated_column_timestamp(timestamp_names)
68
+ if cache_version && timestamp_names.none?
69
+ "#{model_name.cache_key}/#{id}"
61
70
  else
62
- max_updated_column_timestamp
63
- end
71
+ timestamp = if timestamp_names.any?
72
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
73
+ Specifying a timestamp name for #cache_key has been deprecated in favor of
74
+ the explicit #cache_version method that can be overwritten.
75
+ MSG
64
76
 
65
- if timestamp
66
- timestamp = timestamp.utc.to_s(cache_timestamp_format)
67
- "#{model_name.cache_key}/#{id}-#{timestamp}"
68
- else
69
- "#{model_name.cache_key}/#{id}"
77
+ max_updated_column_timestamp(timestamp_names)
78
+ else
79
+ max_updated_column_timestamp
80
+ end
81
+
82
+ if timestamp
83
+ timestamp = timestamp.utc.to_s(cache_timestamp_format)
84
+ "#{model_name.cache_key}/#{id}-#{timestamp}"
85
+ else
86
+ "#{model_name.cache_key}/#{id}"
87
+ end
70
88
  end
71
89
  end
72
90
  end
73
91
 
92
+ # Returns a cache version that can be used together with the cache key to form
93
+ # a recyclable caching scheme. By default, the #updated_at column is used for the
94
+ # cache_version, but this method can be overwritten to return something else.
95
+ #
96
+ # Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
97
+ # +false+ (which it is by default until Rails 6.0).
98
+ def cache_version
99
+ if cache_versioning && timestamp = try(:updated_at)
100
+ timestamp.utc.to_s(:usec)
101
+ end
102
+ end
103
+
104
+ # Returns a cache key along with the version.
105
+ def cache_key_with_version
106
+ if version = cache_version
107
+ "#{cache_key}-#{version}"
108
+ else
109
+ cache_key
110
+ end
111
+ end
112
+
74
113
  module ClassMethods
75
114
  # Defines your model's +to_param+ method to generate "pretty" URLs
76
115
  # using +method_name+, which can be any attribute or method that
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_record/scoping/default"
2
4
  require "active_record/scoping/named"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module LegacyYamlAdapter
3
5
  def self.convert(klass, coder)
@@ -6,7 +8,7 @@ module ActiveRecord
6
8
  case coder["active_record_yaml_version"]
7
9
  when 1, 2 then coder
8
10
  else
9
- if coder["attributes"].is_a?(AttributeSet)
11
+ if coder["attributes"].is_a?(ActiveModel::AttributeSet)
10
12
  Rails420.convert(klass, coder)
11
13
  else
12
14
  Rails41.convert(klass, coder)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Locking
3
5
  # == What is Optimistic Locking
@@ -51,8 +53,7 @@ module ActiveRecord
51
53
  extend ActiveSupport::Concern
52
54
 
53
55
  included do
54
- class_attribute :lock_optimistically, instance_writer: false
55
- self.lock_optimistically = true
56
+ class_attribute :lock_optimistically, instance_writer: false, default: true
56
57
  end
57
58
 
58
59
  def locking_enabled? #:nodoc:
@@ -85,8 +86,8 @@ module ActiveRecord
85
86
 
86
87
  self[locking_column] += 1
87
88
 
88
- affected_rows = self.class.unscoped._update_record(
89
- arel_attributes_with_values(attribute_names),
89
+ affected_rows = self.class._update_record(
90
+ attributes_with_values(attribute_names),
90
91
  self.class.primary_key => id_in_database,
91
92
  locking_column => previous_lock_value
92
93
  )
@@ -105,24 +106,20 @@ module ActiveRecord
105
106
  end
106
107
 
107
108
  def destroy_row
108
- affected_rows = super
109
+ return super unless locking_enabled?
109
110
 
110
- if locking_enabled? && affected_rows != 1
111
- raise ActiveRecord::StaleObjectError.new(self, "destroy")
112
- end
111
+ locking_column = self.class.locking_column
113
112
 
114
- affected_rows
115
- end
113
+ affected_rows = self.class._delete_record(
114
+ self.class.primary_key => id_in_database,
115
+ locking_column => read_attribute_before_type_cast(locking_column)
116
+ )
116
117
 
117
- def relation_for_destroy
118
- relation = super
119
-
120
- if locking_enabled?
121
- locking_column = self.class.locking_column
122
- relation = relation.where(locking_column => read_attribute_before_type_cast(locking_column))
118
+ if affected_rows != 1
119
+ raise ActiveRecord::StaleObjectError.new(self, "destroy")
123
120
  end
124
121
 
125
- relation
122
+ affected_rows
126
123
  end
127
124
 
128
125
  module ClassMethods
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  module Locking
3
5
  # Locking::Pessimistic provides support for row-level locking using
@@ -51,8 +53,8 @@ module ActiveRecord
51
53
  # end
52
54
  #
53
55
  # Database-specific information on row locking:
54
- # MySQL: http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
55
- # PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
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
58
  module Pessimistic
57
59
  # Obtain a row lock on this record. Reloads the record to obtain the requested
58
60
  # lock. Pass an SQL locking clause to append the end of the SELECT statement
@@ -61,12 +63,13 @@ module ActiveRecord
61
63
  def lock!(lock = true)
62
64
  if persisted?
63
65
  if has_changes_to_save?
64
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
65
- Locking a record with unpersisted changes is deprecated and will raise an
66
- exception in Rails 5.2. Use `save` to persist the changes, or `reload` to
67
- discard them explicitly.
66
+ raise(<<-MSG.squish)
67
+ Locking a record with unpersisted changes is not supported. Use
68
+ `save` to persist the changes, or `reload` to discard them
69
+ explicitly.
68
70
  MSG
69
71
  end
72
+
70
73
  reload(lock: lock)
71
74
  end
72
75
  self
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveRecord
2
4
  class LogSubscriber < ActiveSupport::LogSubscriber
3
5
  IGNORE_PAYLOAD_NAMES = ["SCHEMA", "EXPLAIN"]
@@ -88,6 +90,47 @@ module ActiveRecord
88
90
  def logger
89
91
  ActiveRecord::Base.logger
90
92
  end
93
+
94
+ def debug(progname = nil, &block)
95
+ return unless super
96
+
97
+ if ActiveRecord::Base.verbose_query_logs
98
+ log_query_source
99
+ end
100
+ end
101
+
102
+ 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
114
+
115
+ def extract_callstack(callstack)
116
+ line = callstack.find do |frame|
117
+ frame.absolute_path && !ignored_callstack(frame.absolute_path)
118
+ end
119
+
120
+ offending_line = line || callstack.first
121
+
122
+ [
123
+ offending_line.path,
124
+ offending_line.lineno
125
+ ]
126
+ end
127
+
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"])
133
+ end
91
134
  end
92
135
  end
93
136
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "set"
2
4
  require "zlib"
3
5
  require "active_support/core_ext/module/attribute_accessors"
@@ -138,6 +140,7 @@ module ActiveRecord
138
140
 
139
141
  class ConcurrentMigrationError < MigrationError #:nodoc:
140
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
141
144
 
142
145
  def initialize(message = DEFAULT_MESSAGE)
143
146
  super
@@ -157,7 +160,7 @@ module ActiveRecord
157
160
 
158
161
  class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
159
162
  def initialize(env = "production")
160
- msg = "You are attempting to run a destructive action against your '#{env}' database.\n"
163
+ msg = "You are attempting to run a destructive action against your '#{env}' database.\n".dup
161
164
  msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
162
165
  msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
163
166
  super(msg)
@@ -166,7 +169,7 @@ module ActiveRecord
166
169
 
167
170
  class EnvironmentMismatchError < ActiveRecordError
168
171
  def initialize(current: nil, stored: nil)
169
- msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
172
+ msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n".dup
170
173
  msg << "You are running in `#{ current }` environment. "
171
174
  msg << "If you are sure you want to continue, first set the environment using:\n\n"
172
175
  msg << " bin/rails db:environment:set"
@@ -352,9 +355,9 @@ module ActiveRecord
352
355
  # to match the structure of your database.
353
356
  #
354
357
  # To roll the database back to a previous migration version, use
355
- # <tt>rails db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
358
+ # <tt>rails db:rollback VERSION=X</tt> where <tt>X</tt> is the version to which
356
359
  # you wish to downgrade. Alternatively, you can also use the STEP option if you
357
- # wish to rollback last few migrations. <tt>rails db:migrate STEP=2</tt> will rollback
360
+ # wish to rollback last few migrations. <tt>rails db:rollback STEP=2</tt> will rollback
358
361
  # the latest two migrations.
359
362
  #
360
363
  # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
@@ -548,7 +551,7 @@ module ActiveRecord
548
551
  end
549
552
 
550
553
  def call(env)
551
- mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
554
+ mtime = ActiveRecord::Base.connection.migration_context.last_migration.mtime.to_i
552
555
  if @last_check < mtime
553
556
  ActiveRecord::Migration.check_pending!(connection)
554
557
  @last_check = mtime
@@ -573,13 +576,14 @@ module ActiveRecord
573
576
 
574
577
  # Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
575
578
  def check_pending!(connection = Base.connection)
576
- raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
579
+ raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
577
580
  end
578
581
 
579
582
  def load_schema_if_pending!
580
- if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
583
+ if Base.connection.migration_context.needs_migration? || !Base.connection.migration_context.any_migrations?
581
584
  # Roundtrip to Rake to allow plugins to hook into database initialization.
582
- FileUtils.cd Rails.root do
585
+ root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
586
+ FileUtils.cd(root) do
583
587
  current_config = Base.connection_config
584
588
  Base.clear_all_connections!
585
589
  system("bin/rails db:test:prepare")
@@ -731,6 +735,24 @@ module ActiveRecord
731
735
  execute_block { yield helper }
732
736
  end
733
737
 
738
+ # Used to specify an operation that is only run when migrating up
739
+ # (for example, populating a new column with its initial values).
740
+ #
741
+ # In the following example, the new column +published+ will be given
742
+ # the value +true+ for all existing records.
743
+ #
744
+ # class AddPublishedToPosts < ActiveRecord::Migration[5.2]
745
+ # def change
746
+ # add_column :posts, :published, :boolean, default: false
747
+ # up_only do
748
+ # execute "update posts set published = 'true'"
749
+ # end
750
+ # end
751
+ # end
752
+ def up_only
753
+ execute_block { yield } unless reverting?
754
+ end
755
+
734
756
  # Runs the given migration classes.
735
757
  # Last argument can specify options:
736
758
  # - :direction (default is :up)
@@ -855,23 +877,25 @@ module ActiveRecord
855
877
 
856
878
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
857
879
 
858
- destination_migrations = ActiveRecord::Migrator.migrations(destination)
880
+ destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
859
881
  last = destination_migrations.last
860
882
  sources.each do |scope, path|
861
- source_migrations = ActiveRecord::Migrator.migrations(path)
883
+ source_migrations = ActiveRecord::MigrationContext.new(path).migrations
862
884
 
863
885
  source_migrations.each do |migration|
864
886
  source = File.binread(migration.filename)
865
887
  inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
866
- if /\A#.*\b(?:en)?coding:\s*\S+/ =~ source
888
+ magic_comments = "".dup
889
+ loop do
867
890
  # If we have a magic comment in the original migration,
868
891
  # insert our comment after the first newline(end of the magic comment line)
869
892
  # so the magic keep working.
870
893
  # Note that magic comments must be at the first line(except sh-bang).
871
- source[/\n/] = "\n#{inserted_comment}"
872
- else
873
- source = "#{inserted_comment}#{source}"
894
+ source.sub!(/\A(?:#.*\b(?:en)?coding:\s*\S+|#\s*frozen_string_literal:\s*(?:true|false)).*\n/) do |magic_comment|
895
+ magic_comments << magic_comment; ""
896
+ end || break
874
897
  end
898
+ source = "#{magic_comments}#{inserted_comment}#{source}"
875
899
 
876
900
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
877
901
  if options[:on_skip] && duplicate.scope != scope.to_s
@@ -974,146 +998,184 @@ module ActiveRecord
974
998
  end
975
999
  end
976
1000
 
977
- class Migrator#:nodoc:
978
- class << self
979
- attr_writer :migrations_paths
980
- alias :migrations_path= :migrations_paths=
981
-
982
- def migrate(migrations_paths, target_version = nil, &block)
983
- case
984
- when target_version.nil?
985
- up(migrations_paths, target_version, &block)
986
- when current_version == 0 && target_version == 0
987
- []
988
- when current_version > target_version
989
- down(migrations_paths, target_version, &block)
990
- else
991
- up(migrations_paths, target_version, &block)
992
- end
993
- end
1001
+ class MigrationContext # :nodoc:
1002
+ attr_reader :migrations_paths
994
1003
 
995
- def rollback(migrations_paths, steps = 1)
996
- move(:down, migrations_paths, steps)
997
- end
1004
+ def initialize(migrations_paths)
1005
+ @migrations_paths = migrations_paths
1006
+ end
998
1007
 
999
- def forward(migrations_paths, steps = 1)
1000
- move(:up, migrations_paths, steps)
1008
+ def migrate(target_version = nil, &block)
1009
+ case
1010
+ when target_version.nil?
1011
+ up(target_version, &block)
1012
+ when current_version == 0 && target_version == 0
1013
+ []
1014
+ when current_version > target_version
1015
+ down(target_version, &block)
1016
+ else
1017
+ up(target_version, &block)
1001
1018
  end
1019
+ end
1020
+
1021
+ def rollback(steps = 1)
1022
+ move(:down, steps)
1023
+ end
1002
1024
 
1003
- def up(migrations_paths, target_version = nil)
1004
- migrations = migrations(migrations_paths)
1005
- migrations.select! { |m| yield m } if block_given?
1025
+ def forward(steps = 1)
1026
+ move(:up, steps)
1027
+ end
1006
1028
 
1007
- new(:up, migrations, target_version).migrate
1029
+ def up(target_version = nil)
1030
+ selected_migrations = if block_given?
1031
+ migrations.select { |m| yield m }
1032
+ else
1033
+ migrations
1008
1034
  end
1009
1035
 
1010
- def down(migrations_paths, target_version = nil)
1011
- migrations = migrations(migrations_paths)
1012
- migrations.select! { |m| yield m } if block_given?
1036
+ Migrator.new(:up, selected_migrations, target_version).migrate
1037
+ end
1013
1038
 
1014
- new(:down, migrations, target_version).migrate
1039
+ def down(target_version = nil)
1040
+ selected_migrations = if block_given?
1041
+ migrations.select { |m| yield m }
1042
+ else
1043
+ migrations
1015
1044
  end
1016
1045
 
1017
- def run(direction, migrations_paths, target_version)
1018
- new(direction, migrations(migrations_paths), target_version).run
1019
- end
1046
+ Migrator.new(:down, selected_migrations, target_version).migrate
1047
+ end
1020
1048
 
1021
- def open(migrations_paths)
1022
- new(:up, migrations(migrations_paths), nil)
1023
- end
1049
+ def run(direction, target_version)
1050
+ Migrator.new(direction, migrations, target_version).run
1051
+ end
1024
1052
 
1025
- def schema_migrations_table_name
1026
- SchemaMigration.table_name
1027
- end
1028
- deprecate :schema_migrations_table_name
1053
+ def open
1054
+ Migrator.new(:up, migrations, nil)
1055
+ end
1029
1056
 
1030
- def get_all_versions(connection = Base.connection)
1031
- if SchemaMigration.table_exists?
1032
- SchemaMigration.all_versions.map(&:to_i)
1033
- else
1034
- []
1035
- end
1057
+ def get_all_versions
1058
+ if SchemaMigration.table_exists?
1059
+ SchemaMigration.all_versions.map(&:to_i)
1060
+ else
1061
+ []
1036
1062
  end
1063
+ end
1037
1064
 
1038
- def current_version(connection = Base.connection)
1039
- get_all_versions(connection).max || 0
1040
- end
1065
+ def current_version
1066
+ get_all_versions.max || 0
1067
+ rescue ActiveRecord::NoDatabaseError
1068
+ end
1041
1069
 
1042
- def needs_migration?(connection = Base.connection)
1043
- (migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
1044
- end
1070
+ def needs_migration?
1071
+ (migrations.collect(&:version) - get_all_versions).size > 0
1072
+ end
1045
1073
 
1046
- def any_migrations?
1047
- migrations(migrations_paths).any?
1048
- end
1074
+ def any_migrations?
1075
+ migrations.any?
1076
+ end
1049
1077
 
1050
- def last_migration #:nodoc:
1051
- migrations(migrations_paths).last || NullMigration.new
1052
- end
1078
+ def last_migration #:nodoc:
1079
+ migrations.last || NullMigration.new
1080
+ end
1053
1081
 
1054
- def migrations_paths
1055
- @migrations_paths ||= ["db/migrate"]
1056
- # just to not break things if someone uses: migrations_path = some_string
1057
- Array(@migrations_paths)
1058
- end
1082
+ def parse_migration_filename(filename) # :nodoc:
1083
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1084
+ end
1059
1085
 
1060
- def parse_migration_filename(filename) # :nodoc:
1061
- File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1086
+ def migrations
1087
+ migrations = migration_files.map do |file|
1088
+ version, name, scope = parse_migration_filename(file)
1089
+ raise IllegalMigrationNameError.new(file) unless version
1090
+ version = version.to_i
1091
+ name = name.camelize
1092
+
1093
+ MigrationProxy.new(name, version, file, scope)
1062
1094
  end
1063
1095
 
1064
- def migrations(paths)
1065
- paths = Array(paths)
1096
+ migrations.sort_by(&:version)
1097
+ end
1066
1098
 
1067
- migrations = migration_files(paths).map do |file|
1068
- version, name, scope = parse_migration_filename(file)
1069
- raise IllegalMigrationNameError.new(file) unless version
1070
- version = version.to_i
1071
- name = name.camelize
1099
+ def migrations_status
1100
+ db_list = ActiveRecord::SchemaMigration.normalized_versions
1072
1101
 
1073
- MigrationProxy.new(name, version, file, scope)
1074
- end
1102
+ file_list = migration_files.map do |file|
1103
+ version, name, scope = parse_migration_filename(file)
1104
+ raise IllegalMigrationNameError.new(file) unless version
1105
+ version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
1106
+ status = db_list.delete(version) ? "up" : "down"
1107
+ [status, version, (name + scope).humanize]
1108
+ end.compact
1075
1109
 
1076
- migrations.sort_by(&:version)
1110
+ db_list.map! do |version|
1111
+ ["up", version, "********** NO FILE **********"]
1077
1112
  end
1078
1113
 
1079
- def migrations_status(paths)
1080
- paths = Array(paths)
1114
+ (db_list + file_list).sort_by { |_, version, _| version }
1115
+ end
1116
+
1117
+ def migration_files
1118
+ paths = Array(migrations_paths)
1119
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1120
+ end
1121
+
1122
+ def current_environment
1123
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1124
+ end
1125
+
1126
+ def protected_environment?
1127
+ ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1128
+ end
1129
+
1130
+ def last_stored_environment
1131
+ return nil if current_version == 0
1132
+ raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1081
1133
 
1082
- db_list = ActiveRecord::SchemaMigration.normalized_versions
1134
+ environment = ActiveRecord::InternalMetadata[:environment]
1135
+ raise NoEnvironmentInSchemaError unless environment
1136
+ environment
1137
+ end
1083
1138
 
1084
- file_list = migration_files(paths).map do |file|
1085
- version, name, scope = parse_migration_filename(file)
1086
- raise IllegalMigrationNameError.new(file) unless version
1087
- version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
1088
- status = db_list.delete(version) ? "up" : "down"
1089
- [status, version, (name + scope).humanize]
1090
- end.compact
1139
+ private
1140
+ def move(direction, steps)
1141
+ migrator = Migrator.new(direction, migrations)
1091
1142
 
1092
- db_list.map! do |version|
1093
- ["up", version, "********** NO FILE **********"]
1143
+ if current_version != 0 && !migrator.current_migration
1144
+ raise UnknownMigrationVersionError.new(current_version)
1094
1145
  end
1095
1146
 
1096
- (db_list + file_list).sort_by { |_, version, _| version }
1097
- end
1147
+ start_index =
1148
+ if current_version == 0
1149
+ 0
1150
+ else
1151
+ migrator.migrations.index(migrator.current_migration)
1152
+ end
1098
1153
 
1099
- def migration_files(paths)
1100
- Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1154
+ finish = migrator.migrations[start_index + steps]
1155
+ version = finish ? finish.version : 0
1156
+ send(direction, version)
1101
1157
  end
1158
+ end
1102
1159
 
1103
- private
1160
+ class Migrator # :nodoc:
1161
+ class << self
1162
+ attr_accessor :migrations_paths
1104
1163
 
1105
- def move(direction, migrations_paths, steps)
1106
- migrator = new(direction, migrations(migrations_paths))
1107
- start_index = migrator.migrations.index(migrator.current_migration)
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
1108
1170
 
1109
- if start_index
1110
- finish = migrator.migrations[start_index + steps]
1111
- version = finish ? finish.version : 0
1112
- send(direction, migrations_paths, version)
1113
- end
1171
+ # For cases where a table doesn't exist like loading from schema cache
1172
+ def current_version
1173
+ MigrationContext.new(migrations_paths).current_version
1114
1174
  end
1115
1175
  end
1116
1176
 
1177
+ self.migrations_paths = ["db/migrate"]
1178
+
1117
1179
  def initialize(direction, migrations, target_version = nil)
1118
1180
  @direction = direction
1119
1181
  @target_version = target_version
@@ -1176,7 +1238,7 @@ module ActiveRecord
1176
1238
  end
1177
1239
 
1178
1240
  def load_migrated
1179
- @migrated_versions = Set.new(self.class.get_all_versions)
1241
+ @migrated_versions = Set.new(Base.connection.migration_context.get_all_versions)
1180
1242
  end
1181
1243
 
1182
1244
  private
@@ -1208,7 +1270,7 @@ module ActiveRecord
1208
1270
  # Stores the current environment in the database.
1209
1271
  def record_environment
1210
1272
  return if down?
1211
- ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
1273
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
1212
1274
  end
1213
1275
 
1214
1276
  def ran?(migration)
@@ -1217,7 +1279,7 @@ module ActiveRecord
1217
1279
 
1218
1280
  # Return true if a valid version is not provided.
1219
1281
  def invalid_target?
1220
- !target && @target_version && @target_version > 0
1282
+ @target_version && @target_version != 0 && !target
1221
1283
  end
1222
1284
 
1223
1285
  def execute_migration_in_transaction(migration, direction)
@@ -1231,7 +1293,7 @@ module ActiveRecord
1231
1293
  record_version_state_after_migrating(migration.version)
1232
1294
  end
1233
1295
  rescue => e
1234
- msg = "An error has occurred, "
1296
+ msg = "An error has occurred, ".dup
1235
1297
  msg << "this and " if use_transaction?(migration)
1236
1298
  msg << "all later migrations canceled:\n\n#{e}"
1237
1299
  raise StandardError, msg, e.backtrace
@@ -1250,10 +1312,10 @@ module ActiveRecord
1250
1312
  end
1251
1313
 
1252
1314
  def validate(migrations)
1253
- name , = migrations.group_by(&:name).find { |_, v| v.length > 1 }
1315
+ name, = migrations.group_by(&:name).find { |_, v| v.length > 1 }
1254
1316
  raise DuplicateMigrationNameError.new(name) if name
1255
1317
 
1256
- version , = migrations.group_by(&:version).find { |_, v| v.length > 1 }
1318
+ version, = migrations.group_by(&:version).find { |_, v| v.length > 1 }
1257
1319
  raise DuplicateMigrationVersionError.new(version) if version
1258
1320
  end
1259
1321
 
@@ -1267,23 +1329,6 @@ module ActiveRecord
1267
1329
  end
1268
1330
  end
1269
1331
 
1270
- def self.last_stored_environment
1271
- return nil if current_version == 0
1272
- raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1273
-
1274
- environment = ActiveRecord::InternalMetadata[:environment]
1275
- raise NoEnvironmentInSchemaError unless environment
1276
- environment
1277
- end
1278
-
1279
- def self.current_environment
1280
- ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1281
- end
1282
-
1283
- def self.protected_environment?
1284
- ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1285
- end
1286
-
1287
1332
  def up?
1288
1333
  @direction == :up
1289
1334
  end
@@ -1311,12 +1356,17 @@ module ActiveRecord
1311
1356
 
1312
1357
  def with_advisory_lock
1313
1358
  lock_id = generate_migrator_advisory_lock_id
1314
- got_lock = Base.connection.get_advisory_lock(lock_id)
1359
+ connection = Base.connection
1360
+ got_lock = connection.get_advisory_lock(lock_id)
1315
1361
  raise ConcurrentMigrationError unless got_lock
1316
1362
  load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1317
1363
  yield
1318
1364
  ensure
1319
- Base.connection.release_advisory_lock(lock_id) if got_lock
1365
+ if got_lock && !connection.release_advisory_lock(lock_id)
1366
+ raise ConcurrentMigrationError.new(
1367
+ ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1368
+ )
1369
+ end
1320
1370
  end
1321
1371
 
1322
1372
  MIGRATOR_SALT = 2053462845