activerecord 4.2.0 → 5.2.8.1

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 (274) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +640 -928
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +10 -11
  5. data/examples/performance.rb +32 -31
  6. data/examples/simple.rb +5 -4
  7. data/lib/active_record/aggregations.rb +264 -247
  8. data/lib/active_record/association_relation.rb +24 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +87 -41
  11. data/lib/active_record/associations/association_scope.rb +106 -132
  12. data/lib/active_record/associations/belongs_to_association.rb +55 -36
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +8 -8
  14. data/lib/active_record/associations/builder/association.rb +29 -38
  15. data/lib/active_record/associations/builder/belongs_to.rb +77 -30
  16. data/lib/active_record/associations/builder/collection_association.rb +14 -23
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +50 -39
  18. data/lib/active_record/associations/builder/has_many.rb +6 -4
  19. data/lib/active_record/associations/builder/has_one.rb +13 -6
  20. data/lib/active_record/associations/builder/singular_association.rb +15 -11
  21. data/lib/active_record/associations/collection_association.rb +145 -266
  22. data/lib/active_record/associations/collection_proxy.rb +242 -138
  23. data/lib/active_record/associations/foreign_association.rb +13 -0
  24. data/lib/active_record/associations/has_many_association.rb +35 -75
  25. data/lib/active_record/associations/has_many_through_association.rb +51 -69
  26. data/lib/active_record/associations/has_one_association.rb +39 -24
  27. data/lib/active_record/associations/has_one_through_association.rb +18 -9
  28. data/lib/active_record/associations/join_dependency/join_association.rb +40 -81
  29. data/lib/active_record/associations/join_dependency/join_base.rb +10 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +12 -12
  31. data/lib/active_record/associations/join_dependency.rb +134 -154
  32. data/lib/active_record/associations/preloader/association.rb +85 -116
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +83 -93
  35. data/lib/active_record/associations/singular_association.rb +27 -40
  36. data/lib/active_record/associations/through_association.rb +48 -23
  37. data/lib/active_record/associations.rb +1732 -1596
  38. data/lib/active_record/attribute_assignment.rb +58 -182
  39. data/lib/active_record/attribute_decorators.rb +39 -15
  40. data/lib/active_record/attribute_methods/before_type_cast.rb +12 -5
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -125
  42. data/lib/active_record/attribute_methods/primary_key.rb +86 -71
  43. data/lib/active_record/attribute_methods/query.rb +4 -2
  44. data/lib/active_record/attribute_methods/read.rb +45 -63
  45. data/lib/active_record/attribute_methods/serialization.rb +40 -20
  46. data/lib/active_record/attribute_methods/time_zone_conversion.rb +62 -36
  47. data/lib/active_record/attribute_methods/write.rb +31 -46
  48. data/lib/active_record/attribute_methods.rb +170 -117
  49. data/lib/active_record/attributes.rb +201 -74
  50. data/lib/active_record/autosave_association.rb +118 -45
  51. data/lib/active_record/base.rb +60 -48
  52. data/lib/active_record/callbacks.rb +97 -57
  53. data/lib/active_record/coders/json.rb +3 -1
  54. data/lib/active_record/coders/yaml_column.rb +37 -13
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -284
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +254 -87
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +72 -22
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +119 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +6 -4
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +328 -217
  64. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +81 -36
  65. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +617 -212
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +139 -75
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +332 -191
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +567 -563
  69. data/lib/active_record/connection_adapters/column.rb +50 -41
  70. data/lib/active_record/connection_adapters/connection_specification.rb +147 -135
  71. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +33 -0
  72. data/lib/active_record/connection_adapters/mysql/column.rb +27 -0
  73. data/lib/active_record/connection_adapters/mysql/database_statements.rb +140 -0
  74. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +72 -0
  75. data/lib/active_record/connection_adapters/mysql/quoting.rb +44 -0
  76. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +73 -0
  77. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +87 -0
  78. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +80 -0
  79. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +148 -0
  80. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +35 -0
  81. data/lib/active_record/connection_adapters/mysql2_adapter.rb +42 -195
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +46 -115
  84. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +44 -0
  85. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +50 -57
  86. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +10 -6
  87. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +2 -0
  88. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +5 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +5 -1
  90. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +13 -1
  91. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +9 -13
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +7 -3
  94. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +31 -19
  95. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +2 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +3 -11
  97. data/lib/active_record/connection_adapters/postgresql/oid/legacy_point.rb +45 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +7 -9
  99. data/lib/active_record/connection_adapters/postgresql/oid/{integer.rb → oid.rb} +6 -2
  100. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +33 -11
  101. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +52 -34
  102. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +4 -1
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +65 -51
  104. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +5 -3
  105. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +3 -1
  106. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +3 -1
  107. data/lib/active_record/connection_adapters/postgresql/oid.rb +23 -25
  108. data/lib/active_record/connection_adapters/postgresql/quoting.rb +107 -47
  109. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +27 -14
  110. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +65 -0
  111. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +144 -90
  112. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +50 -0
  113. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +466 -280
  114. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +39 -0
  115. data/lib/active_record/connection_adapters/postgresql/utils.rb +12 -8
  116. data/lib/active_record/connection_adapters/postgresql_adapter.rb +439 -330
  117. data/lib/active_record/connection_adapters/schema_cache.rb +48 -24
  118. data/lib/active_record/connection_adapters/sql_type_metadata.rb +34 -0
  119. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +21 -0
  120. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +67 -0
  121. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +17 -0
  122. data/lib/active_record/connection_adapters/sqlite3/schema_definitions.rb +19 -0
  123. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +18 -0
  124. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +106 -0
  125. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +269 -324
  126. data/lib/active_record/connection_adapters/statement_pool.rb +34 -13
  127. data/lib/active_record/connection_handling.rb +40 -27
  128. data/lib/active_record/core.rb +205 -202
  129. data/lib/active_record/counter_cache.rb +80 -37
  130. data/lib/active_record/define_callbacks.rb +22 -0
  131. data/lib/active_record/dynamic_matchers.rb +87 -105
  132. data/lib/active_record/enum.rb +136 -90
  133. data/lib/active_record/errors.rb +180 -52
  134. data/lib/active_record/explain.rb +23 -11
  135. data/lib/active_record/explain_registry.rb +4 -2
  136. data/lib/active_record/explain_subscriber.rb +11 -6
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +193 -135
  139. data/lib/active_record/gem_version.rb +5 -3
  140. data/lib/active_record/inheritance.rb +148 -112
  141. data/lib/active_record/integration.rb +70 -28
  142. data/lib/active_record/internal_metadata.rb +45 -0
  143. data/lib/active_record/legacy_yaml_adapter.rb +48 -0
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +92 -98
  146. data/lib/active_record/locking/pessimistic.rb +15 -3
  147. data/lib/active_record/log_subscriber.rb +95 -33
  148. data/lib/active_record/migration/command_recorder.rb +133 -90
  149. data/lib/active_record/migration/compatibility.rb +217 -0
  150. data/lib/active_record/migration/join_table.rb +8 -6
  151. data/lib/active_record/migration.rb +594 -267
  152. data/lib/active_record/model_schema.rb +292 -111
  153. data/lib/active_record/nested_attributes.rb +266 -214
  154. data/lib/active_record/no_touching.rb +8 -2
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +350 -119
  157. data/lib/active_record/query_cache.rb +13 -24
  158. data/lib/active_record/querying.rb +19 -17
  159. data/lib/active_record/railtie.rb +117 -35
  160. data/lib/active_record/railties/console_sandbox.rb +2 -0
  161. data/lib/active_record/railties/controller_runtime.rb +9 -3
  162. data/lib/active_record/railties/databases.rake +160 -174
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +447 -288
  165. data/lib/active_record/relation/batches/batch_enumerator.rb +69 -0
  166. data/lib/active_record/relation/batches.rb +204 -55
  167. data/lib/active_record/relation/calculations.rb +259 -244
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +290 -253
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +91 -68
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -23
  173. data/lib/active_record/relation/predicate_builder/association_query_value.rb +46 -0
  174. data/lib/active_record/relation/predicate_builder/base_handler.rb +19 -0
  175. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +20 -0
  176. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +56 -0
  177. data/lib/active_record/relation/predicate_builder/range_handler.rb +42 -0
  178. data/lib/active_record/relation/predicate_builder/relation_handler.rb +7 -1
  179. data/lib/active_record/relation/predicate_builder.rb +118 -92
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +446 -389
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +18 -16
  184. data/lib/active_record/relation/where_clause.rb +186 -0
  185. data/lib/active_record/relation/where_clause_factory.rb +34 -0
  186. data/lib/active_record/relation.rb +287 -339
  187. data/lib/active_record/result.rb +54 -36
  188. data/lib/active_record/runtime_registry.rb +6 -4
  189. data/lib/active_record/sanitization.rb +155 -124
  190. data/lib/active_record/schema.rb +30 -24
  191. data/lib/active_record/schema_dumper.rb +91 -87
  192. data/lib/active_record/schema_migration.rb +19 -19
  193. data/lib/active_record/scoping/default.rb +102 -84
  194. data/lib/active_record/scoping/named.rb +81 -32
  195. data/lib/active_record/scoping.rb +45 -26
  196. data/lib/active_record/secure_token.rb +40 -0
  197. data/lib/active_record/serialization.rb +5 -5
  198. data/lib/active_record/statement_cache.rb +45 -35
  199. data/lib/active_record/store.rb +42 -36
  200. data/lib/active_record/suppressor.rb +61 -0
  201. data/lib/active_record/table_metadata.rb +82 -0
  202. data/lib/active_record/tasks/database_tasks.rb +136 -95
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +59 -89
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +84 -31
  205. data/lib/active_record/tasks/sqlite_database_tasks.rb +44 -16
  206. data/lib/active_record/timestamp.rb +70 -38
  207. data/lib/active_record/touch_later.rb +64 -0
  208. data/lib/active_record/transactions.rb +208 -123
  209. data/lib/active_record/translation.rb +2 -0
  210. data/lib/active_record/type/adapter_specific_registry.rb +136 -0
  211. data/lib/active_record/type/date.rb +4 -41
  212. data/lib/active_record/type/date_time.rb +4 -38
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +13 -5
  215. data/lib/active_record/type/internal/timezone.rb +17 -0
  216. data/lib/active_record/type/json.rb +30 -0
  217. data/lib/active_record/type/serialized.rb +30 -15
  218. data/lib/active_record/type/text.rb +2 -2
  219. data/lib/active_record/type/time.rb +11 -16
  220. data/lib/active_record/type/type_map.rb +15 -17
  221. data/lib/active_record/type/unsigned_integer.rb +9 -7
  222. data/lib/active_record/type.rb +79 -23
  223. data/lib/active_record/type_caster/connection.rb +33 -0
  224. data/lib/active_record/type_caster/map.rb +23 -0
  225. data/lib/active_record/type_caster.rb +9 -0
  226. data/lib/active_record/validations/absence.rb +25 -0
  227. data/lib/active_record/validations/associated.rb +13 -4
  228. data/lib/active_record/validations/length.rb +26 -0
  229. data/lib/active_record/validations/presence.rb +14 -13
  230. data/lib/active_record/validations/uniqueness.rb +41 -32
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +36 -21
  234. data/lib/rails/generators/active_record/application_record/application_record_generator.rb +27 -0
  235. data/lib/rails/generators/active_record/application_record/templates/application_record.rb.tt +5 -0
  236. data/lib/rails/generators/active_record/migration/migration_generator.rb +43 -35
  237. data/lib/rails/generators/active_record/migration/templates/{create_table_migration.rb → create_table_migration.rb.tt} +8 -6
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -7
  239. data/lib/rails/generators/active_record/migration.rb +18 -1
  240. data/lib/rails/generators/active_record/model/model_generator.rb +18 -22
  241. data/lib/rails/generators/active_record/model/templates/{model.rb → model.rb.tt} +3 -0
  242. data/lib/rails/generators/active_record.rb +7 -5
  243. metadata +77 -53
  244. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  245. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  246. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  247. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  248. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  249. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  250. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  251. data/lib/active_record/attribute.rb +0 -149
  252. data/lib/active_record/attribute_set/builder.rb +0 -86
  253. data/lib/active_record/attribute_set.rb +0 -77
  254. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  255. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  256. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  257. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  258. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  259. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  260. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  261. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  262. data/lib/active_record/type/big_integer.rb +0 -13
  263. data/lib/active_record/type/binary.rb +0 -50
  264. data/lib/active_record/type/boolean.rb +0 -30
  265. data/lib/active_record/type/decimal.rb +0 -40
  266. data/lib/active_record/type/decorator.rb +0 -14
  267. data/lib/active_record/type/float.rb +0 -19
  268. data/lib/active_record/type/integer.rb +0 -55
  269. data/lib/active_record/type/mutable.rb +0 -16
  270. data/lib/active_record/type/numeric.rb +0 -36
  271. data/lib/active_record/type/string.rb +0 -36
  272. data/lib/active_record/type/time_value.rb +0 -38
  273. data/lib/active_record/type/value.rb +0 -101
  274. /data/lib/rails/generators/active_record/model/templates/{module.rb → module.rb.tt} +0 -0
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "zlib"
1
5
  require "active_support/core_ext/module/attribute_accessors"
2
- require 'set'
3
6
 
4
7
  module ActiveRecord
5
8
  class MigrationError < ActiveRecordError#:nodoc:
@@ -9,40 +12,171 @@ module ActiveRecord
9
12
  end
10
13
  end
11
14
 
12
- # Exception that can be raised to stop migrations from going backwards.
15
+ # Exception that can be raised to stop migrations from being rolled back.
16
+ # For example the following migration is not reversible.
17
+ # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
18
+ #
19
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[5.0]
20
+ # def change
21
+ # create_table :distributors do |t|
22
+ # t.string :zipcode
23
+ # end
24
+ #
25
+ # execute <<-SQL
26
+ # ALTER TABLE distributors
27
+ # ADD CONSTRAINT zipchk
28
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
29
+ # SQL
30
+ # end
31
+ # end
32
+ #
33
+ # There are two ways to mitigate this problem.
34
+ #
35
+ # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
36
+ #
37
+ # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
38
+ # def up
39
+ # create_table :distributors do |t|
40
+ # t.string :zipcode
41
+ # end
42
+ #
43
+ # execute <<-SQL
44
+ # ALTER TABLE distributors
45
+ # ADD CONSTRAINT zipchk
46
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
47
+ # SQL
48
+ # end
49
+ #
50
+ # def down
51
+ # execute <<-SQL
52
+ # ALTER TABLE distributors
53
+ # DROP CONSTRAINT zipchk
54
+ # SQL
55
+ #
56
+ # drop_table :distributors
57
+ # end
58
+ # end
59
+ #
60
+ # 2. Use the #reversible method in <tt>#change</tt> method:
61
+ #
62
+ # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
63
+ # def change
64
+ # create_table :distributors do |t|
65
+ # t.string :zipcode
66
+ # end
67
+ #
68
+ # reversible do |dir|
69
+ # dir.up do
70
+ # execute <<-SQL
71
+ # ALTER TABLE distributors
72
+ # ADD CONSTRAINT zipchk
73
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
74
+ # SQL
75
+ # end
76
+ #
77
+ # dir.down do
78
+ # execute <<-SQL
79
+ # ALTER TABLE distributors
80
+ # DROP CONSTRAINT zipchk
81
+ # SQL
82
+ # end
83
+ # end
84
+ # end
85
+ # end
13
86
  class IrreversibleMigration < MigrationError
14
87
  end
15
88
 
16
89
  class DuplicateMigrationVersionError < MigrationError#:nodoc:
17
- def initialize(version)
18
- super("Multiple migrations have the version number #{version}")
90
+ def initialize(version = nil)
91
+ if version
92
+ super("Multiple migrations have the version number #{version}.")
93
+ else
94
+ super("Duplicate migration version error.")
95
+ end
19
96
  end
20
97
  end
21
98
 
22
99
  class DuplicateMigrationNameError < MigrationError#:nodoc:
23
- def initialize(name)
24
- super("Multiple migrations have the name #{name}")
100
+ def initialize(name = nil)
101
+ if name
102
+ super("Multiple migrations have the name #{name}.")
103
+ else
104
+ super("Duplicate migration name.")
105
+ end
25
106
  end
26
107
  end
27
108
 
28
109
  class UnknownMigrationVersionError < MigrationError #:nodoc:
29
- def initialize(version)
30
- super("No migration with version number #{version}")
110
+ def initialize(version = nil)
111
+ if version
112
+ super("No migration with version number #{version}.")
113
+ else
114
+ super("Unknown migration version.")
115
+ end
31
116
  end
32
117
  end
33
118
 
34
119
  class IllegalMigrationNameError < MigrationError#:nodoc:
35
- def initialize(name)
36
- super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed)")
120
+ def initialize(name = nil)
121
+ if name
122
+ super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
123
+ else
124
+ super("Illegal name for migration.")
125
+ end
37
126
  end
38
127
  end
39
128
 
40
129
  class PendingMigrationError < MigrationError#:nodoc:
130
+ def initialize(message = nil)
131
+ 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}")
133
+ elsif !message
134
+ super("Migrations are pending. To resolve this issue, run:\n\n bin/rails db:migrate")
135
+ else
136
+ super
137
+ end
138
+ end
139
+ end
140
+
141
+ 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
144
+
145
+ def initialize(message = DEFAULT_MESSAGE)
146
+ super
147
+ end
148
+ end
149
+
150
+ class NoEnvironmentInSchemaError < MigrationError #:nodoc:
41
151
  def initialize
42
- if defined?(Rails)
43
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate RAILS_ENV=#{::Rails.env}")
152
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
153
+ if defined?(Rails.env)
154
+ super("#{msg} RAILS_ENV=#{::Rails.env}")
44
155
  else
45
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate")
156
+ super(msg)
157
+ end
158
+ end
159
+ end
160
+
161
+ class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
162
+ def initialize(env = "production")
163
+ msg = "You are attempting to run a destructive action against your '#{env}' database.\n".dup
164
+ msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
165
+ msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
166
+ super(msg)
167
+ end
168
+ end
169
+
170
+ class EnvironmentMismatchError < ActiveRecordError
171
+ def initialize(current: nil, stored: nil)
172
+ msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n".dup
173
+ msg << "You are running in `#{ current }` environment. "
174
+ msg << "If you are sure you want to continue, first set the environment using:\n\n"
175
+ msg << " bin/rails db:environment:set"
176
+ if defined?(Rails.env)
177
+ super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
178
+ else
179
+ super("#{msg}\n\n")
46
180
  end
47
181
  end
48
182
  end
@@ -59,7 +193,7 @@ module ActiveRecord
59
193
  #
60
194
  # Example of a simple migration:
61
195
  #
62
- # class AddSsl < ActiveRecord::Migration
196
+ # class AddSsl < ActiveRecord::Migration[5.0]
63
197
  # def up
64
198
  # add_column :accounts, :ssl_enabled, :boolean, default: true
65
199
  # end
@@ -79,7 +213,7 @@ module ActiveRecord
79
213
  #
80
214
  # Example of a more complex migration that also needs to initialize data:
81
215
  #
82
- # class AddSystemSettings < ActiveRecord::Migration
216
+ # class AddSystemSettings < ActiveRecord::Migration[5.0]
83
217
  # def up
84
218
  # create_table :system_settings do |t|
85
219
  # t.string :name
@@ -106,17 +240,18 @@ module ActiveRecord
106
240
  #
107
241
  # == Available transformations
108
242
  #
243
+ # === Creation
244
+ #
245
+ # * <tt>create_join_table(table_1, table_2, options)</tt>: Creates a join
246
+ # table having its name as the lexical order of the first two
247
+ # arguments. See
248
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#create_join_table for
249
+ # details.
109
250
  # * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
110
251
  # makes the table object available to a block that can then add columns to it,
111
252
  # following the same format as +add_column+. See example above. The options hash
112
253
  # is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
113
254
  # table definition.
114
- # * <tt>drop_table(name)</tt>: Drops the table called +name+.
115
- # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
116
- # the table called +name+. It makes the table object available to a block that
117
- # can then add/remove columns, indexes or foreign keys to it.
118
- # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
119
- # to +new_name+.
120
255
  # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
121
256
  # to the table called +table_name+
122
257
  # named +column_name+ specified to be one of the following types:
@@ -127,21 +262,61 @@ module ActiveRecord
127
262
  # Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
128
263
  # <tt>{ limit: 50, null: false }</tt>) -- see
129
264
  # ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
130
- # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
131
- # a column but keeps the type and content.
132
- # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
133
- # the column to a different type using the same parameters as add_column.
134
- # * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
135
- # named +column_name+ from the table called +table_name+.
265
+ # * <tt>add_foreign_key(from_table, to_table, options)</tt>: Adds a new
266
+ # foreign key. +from_table+ is the table with the key column, +to_table+ contains
267
+ # the referenced primary key.
136
268
  # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
137
269
  # with the name of the column. Other options include
138
270
  # <tt>:name</tt>, <tt>:unique</tt> (e.g.
139
271
  # <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
140
272
  # (e.g. <tt>{ order: { name: :desc } }</tt>).
141
- # * <tt>remove_index(table_name, column: column_name)</tt>: Removes the index
142
- # specified by +column_name+.
273
+ # * <tt>add_reference(:table_name, :reference_name)</tt>: Adds a new column
274
+ # +reference_name_id+ by default an integer. See
275
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference for details.
276
+ # * <tt>add_timestamps(table_name, options)</tt>: Adds timestamps (+created_at+
277
+ # and +updated_at+) columns to +table_name+.
278
+ #
279
+ # === Modification
280
+ #
281
+ # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
282
+ # the column to a different type using the same parameters as add_column.
283
+ # * <tt>change_column_default(table_name, column_name, default_or_changes)</tt>:
284
+ # Sets a default value for +column_name+ defined by +default_or_changes+ on
285
+ # +table_name+. Passing a hash containing <tt>:from</tt> and <tt>:to</tt>
286
+ # as +default_or_changes+ will make this change reversible in the migration.
287
+ # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
288
+ # Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
289
+ # indicates whether the value can be +NULL+. See
290
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
291
+ # details.
292
+ # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
293
+ # the table called +name+. It makes the table object available to a block that
294
+ # can then add/remove columns, indexes or foreign keys to it.
295
+ # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
296
+ # a column but keeps the type and content.
297
+ # * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
298
+ # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
299
+ # to +new_name+.
300
+ #
301
+ # === Deletion
302
+ #
303
+ # * <tt>drop_table(name)</tt>: Drops the table called +name+.
304
+ # * <tt>drop_join_table(table_1, table_2, options)</tt>: Drops the join table
305
+ # specified by the given arguments.
306
+ # * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
307
+ # named +column_name+ from the table called +table_name+.
308
+ # * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
309
+ # columns from the table definition.
310
+ # * <tt>remove_foreign_key(from_table, options_or_to_table)</tt>: Removes the
311
+ # given foreign key from the table called +table_name+.
312
+ # * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
313
+ # specified by +column_names+.
143
314
  # * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
144
315
  # specified by +index_name+.
316
+ # * <tt>remove_reference(table_name, ref_name, options)</tt>: Removes the
317
+ # reference(s) on +table_name+ specified by +ref_name+.
318
+ # * <tt>remove_timestamps(table_name, options)</tt>: Removes the timestamp
319
+ # columns (+created_at+ and +updated_at+) from the table definition.
145
320
  #
146
321
  # == Irreversible transformations
147
322
  #
@@ -165,24 +340,24 @@ module ActiveRecord
165
340
  #
166
341
  # rails generate migration add_fieldname_to_tablename fieldname:string
167
342
  #
168
- # This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
169
- # class AddFieldnameToTablename < ActiveRecord::Migration
343
+ # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
344
+ # class AddFieldnameToTablename < ActiveRecord::Migration[5.0]
170
345
  # def change
171
- # add_column :tablenames, :field, :string
346
+ # add_column :tablenames, :fieldname, :string
172
347
  # end
173
348
  # end
174
349
  #
175
350
  # To run migrations against the currently configured database, use
176
- # <tt>rake db:migrate</tt>. This will update the database by running all of the
351
+ # <tt>rails db:migrate</tt>. This will update the database by running all of the
177
352
  # pending migrations, creating the <tt>schema_migrations</tt> table
178
353
  # (see "About the schema_migrations table" section below) if missing. It will also
179
354
  # invoke the db:schema:dump task, which will update your db/schema.rb file
180
355
  # to match the structure of your database.
181
356
  #
182
357
  # To roll the database back to a previous migration version, use
183
- # <tt>rake 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
184
359
  # you wish to downgrade. Alternatively, you can also use the STEP option if you
185
- # wish to rollback last few migrations. <tt>rake db:migrate STEP=2</tt> will rollback
360
+ # wish to rollback last few migrations. <tt>rails db:rollback STEP=2</tt> will rollback
186
361
  # the latest two migrations.
187
362
  #
188
363
  # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
@@ -197,7 +372,7 @@ module ActiveRecord
197
372
  #
198
373
  # Not all migrations change the schema. Some just fix the data:
199
374
  #
200
- # class RemoveEmptyTags < ActiveRecord::Migration
375
+ # class RemoveEmptyTags < ActiveRecord::Migration[5.0]
201
376
  # def up
202
377
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
203
378
  # end
@@ -210,7 +385,7 @@ module ActiveRecord
210
385
  #
211
386
  # Others remove columns when they migrate up instead of down:
212
387
  #
213
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
388
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[5.0]
214
389
  # def up
215
390
  # remove_column :items, :incomplete_items_count
216
391
  # remove_column :items, :completed_items_count
@@ -224,7 +399,7 @@ module ActiveRecord
224
399
  #
225
400
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
226
401
  #
227
- # class MakeJoinUnique < ActiveRecord::Migration
402
+ # class MakeJoinUnique < ActiveRecord::Migration[5.0]
228
403
  # def up
229
404
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
230
405
  # end
@@ -241,7 +416,7 @@ module ActiveRecord
241
416
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
242
417
  # latest column data from after the new column was added. Example:
243
418
  #
244
- # class AddPeopleSalary < ActiveRecord::Migration
419
+ # class AddPeopleSalary < ActiveRecord::Migration[5.0]
245
420
  # def up
246
421
  # add_column :people, :salary, :integer
247
422
  # Person.reset_column_information
@@ -275,21 +450,6 @@ module ActiveRecord
275
450
  # The phrase "Updating salaries..." would then be printed, along with the
276
451
  # benchmark for the block when the block completes.
277
452
  #
278
- # == About the schema_migrations table
279
- #
280
- # Rails versions 2.0 and prior used to create a table called
281
- # <tt>schema_info</tt> when using migrations. This table contained the
282
- # version of the schema as of the last applied migration.
283
- #
284
- # Starting with Rails 2.1, the <tt>schema_info</tt> table is
285
- # (automatically) replaced by the <tt>schema_migrations</tt> table, which
286
- # contains the version numbers of all the migrations applied.
287
- #
288
- # As a result, it is now possible to add migration files that are numbered
289
- # lower than the current schema version: when migrating up, those
290
- # never-applied "interleaved" migrations will be automatically applied, and
291
- # when migrating down, never-applied "interleaved" migrations will be skipped.
292
- #
293
453
  # == Timestamped Migrations
294
454
  #
295
455
  # By default, Rails generates migrations that look like:
@@ -307,15 +467,14 @@ module ActiveRecord
307
467
  #
308
468
  # == Reversible Migrations
309
469
  #
310
- # Starting with Rails 3.1, you will be able to define reversible migrations.
311
470
  # Reversible migrations are migrations that know how to go +down+ for you.
312
- # You simply supply the +up+ logic, and the Migration system will figure out
471
+ # You simply supply the +up+ logic, and the Migration system figures out
313
472
  # how to execute the down commands for you.
314
473
  #
315
474
  # To define a reversible migration, define the +change+ method in your
316
475
  # migration like this:
317
476
  #
318
- # class TenderloveMigration < ActiveRecord::Migration
477
+ # class TenderloveMigration < ActiveRecord::Migration[5.0]
319
478
  # def change
320
479
  # create_table(:horses) do |t|
321
480
  # t.column :content, :text
@@ -345,7 +504,7 @@ module ActiveRecord
345
504
  # can't execute inside a transaction though, and for these situations
346
505
  # you can turn the automatic transactions off.
347
506
  #
348
- # class ChangeEnum < ActiveRecord::Migration
507
+ # class ChangeEnum < ActiveRecord::Migration[5.0]
349
508
  # disable_ddl_transaction!
350
509
  #
351
510
  # def up
@@ -356,11 +515,35 @@ module ActiveRecord
356
515
  # Remember that you can still open your own transactions, even if you
357
516
  # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
358
517
  class Migration
359
- autoload :CommandRecorder, 'active_record/migration/command_recorder'
518
+ autoload :CommandRecorder, "active_record/migration/command_recorder"
519
+ autoload :Compatibility, "active_record/migration/compatibility"
360
520
 
521
+ # This must be defined before the inherited hook, below
522
+ class Current < Migration # :nodoc:
523
+ end
524
+
525
+ def self.inherited(subclass) # :nodoc:
526
+ super
527
+ if subclass.superclass == Migration
528
+ raise StandardError, "Directly inheriting from ActiveRecord::Migration is not supported. " \
529
+ "Please specify the Rails release the migration was written for:\n" \
530
+ "\n" \
531
+ " class #{subclass} < ActiveRecord::Migration[4.2]"
532
+ end
533
+ end
534
+
535
+ def self.[](version)
536
+ Compatibility.find(version)
537
+ end
538
+
539
+ def self.current_version
540
+ ActiveRecord::VERSION::STRING.to_f
541
+ end
542
+
543
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
361
544
 
362
545
  # This class is used to verify that all migrations have been run before
363
- # loading a web page if config.active_record.migration_error is set to :page_load
546
+ # loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
364
547
  class CheckPending
365
548
  def initialize(app)
366
549
  @app = app
@@ -368,38 +551,42 @@ module ActiveRecord
368
551
  end
369
552
 
370
553
  def call(env)
371
- if connection.supports_migrations?
372
- mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
373
- if @last_check < mtime
374
- ActiveRecord::Migration.check_pending!(connection)
375
- @last_check = mtime
376
- end
554
+ mtime = ActiveRecord::Base.connection.migration_context.last_migration.mtime.to_i
555
+ if @last_check < mtime
556
+ ActiveRecord::Migration.check_pending!(connection)
557
+ @last_check = mtime
377
558
  end
378
559
  @app.call(env)
379
560
  end
380
561
 
381
562
  private
382
563
 
383
- def connection
384
- ActiveRecord::Base.connection
385
- end
564
+ def connection
565
+ ActiveRecord::Base.connection
566
+ end
386
567
  end
387
568
 
388
569
  class << self
389
570
  attr_accessor :delegate # :nodoc:
390
571
  attr_accessor :disable_ddl_transaction # :nodoc:
391
572
 
573
+ def nearest_delegate # :nodoc:
574
+ delegate || superclass.nearest_delegate
575
+ end
576
+
577
+ # Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
392
578
  def check_pending!(connection = Base.connection)
393
- raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
579
+ raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
394
580
  end
395
581
 
396
582
  def load_schema_if_pending!
397
- if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
398
- # Roundrip to Rake to allow plugins to hook into database initialization.
399
- FileUtils.cd Rails.root do
583
+ if Base.connection.migration_context.needs_migration? || !Base.connection.migration_context.any_migrations?
584
+ # Roundtrip to Rake to allow plugins to hook into database initialization.
585
+ root = defined?(ENGINE_ROOT) ? ENGINE_ROOT : Rails.root
586
+ FileUtils.cd(root) do
400
587
  current_config = Base.connection_config
401
588
  Base.clear_all_connections!
402
- system("bin/rake db:test:prepare")
589
+ system("bin/rails db:test:prepare")
403
590
  # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
404
591
  Base.establish_connection(current_config)
405
592
  end
@@ -414,14 +601,17 @@ module ActiveRecord
414
601
  end
415
602
 
416
603
  def method_missing(name, *args, &block) # :nodoc:
417
- (delegate || superclass.delegate).send(name, *args, &block)
604
+ nearest_delegate.send(name, *args, &block)
418
605
  end
419
606
 
420
607
  def migrate(direction)
421
608
  new.migrate direction
422
609
  end
423
610
 
424
- # Disable DDL transactions for this migration.
611
+ # Disable the transaction wrapping this migration.
612
+ # You can still create your own transactions even after calling #disable_ddl_transaction!
613
+ #
614
+ # For more details read the {"Transactional Migrations" section above}[rdoc-ref:Migration].
425
615
  def disable_ddl_transaction!
426
616
  @disable_ddl_transaction = true
427
617
  end
@@ -451,7 +641,7 @@ module ActiveRecord
451
641
  # and create the table 'apples' on the way up, and the reverse
452
642
  # on the way down.
453
643
  #
454
- # class FixTLMigration < ActiveRecord::Migration
644
+ # class FixTLMigration < ActiveRecord::Migration[5.0]
455
645
  # def change
456
646
  # revert do
457
647
  # create_table(:horses) do |t|
@@ -468,9 +658,9 @@ module ActiveRecord
468
658
  # Or equivalently, if +TenderloveMigration+ is defined as in the
469
659
  # documentation for Migration:
470
660
  #
471
- # require_relative '2012121212_tenderlove_migration'
661
+ # require_relative '20121212123456_tenderlove_migration'
472
662
  #
473
- # class FixupTLMigration < ActiveRecord::Migration
663
+ # class FixupTLMigration < ActiveRecord::Migration[5.0]
474
664
  # def change
475
665
  # revert TenderloveMigration
476
666
  #
@@ -484,13 +674,13 @@ module ActiveRecord
484
674
  def revert(*migration_classes)
485
675
  run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
486
676
  if block_given?
487
- if @connection.respond_to? :revert
488
- @connection.revert { yield }
677
+ if connection.respond_to? :revert
678
+ connection.revert { yield }
489
679
  else
490
- recorder = CommandRecorder.new(@connection)
680
+ recorder = CommandRecorder.new(connection)
491
681
  @connection = recorder
492
682
  suppress_messages do
493
- @connection.revert { yield }
683
+ connection.revert { yield }
494
684
  end
495
685
  @connection = recorder.delegate
496
686
  recorder.commands.each do |cmd, args, block|
@@ -501,10 +691,10 @@ module ActiveRecord
501
691
  end
502
692
 
503
693
  def reverting?
504
- @connection.respond_to?(:reverting) && @connection.reverting
694
+ connection.respond_to?(:reverting) && connection.reverting
505
695
  end
506
696
 
507
- class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
697
+ ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
508
698
  def up
509
699
  yield unless reverting
510
700
  end
@@ -523,7 +713,7 @@ module ActiveRecord
523
713
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
524
714
  # even when migrating down:
525
715
  #
526
- # class SplitNameMigration < ActiveRecord::Migration
716
+ # class SplitNameMigration < ActiveRecord::Migration[5.0]
527
717
  # def change
528
718
  # add_column :users, :first_name, :string
529
719
  # add_column :users, :last_name, :string
@@ -542,7 +732,25 @@ module ActiveRecord
542
732
  # end
543
733
  def reversible
544
734
  helper = ReversibleBlockHelper.new(reverting?)
545
- execute_block{ yield helper }
735
+ execute_block { yield helper }
736
+ end
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?
546
754
  end
547
755
 
548
756
  # Runs the given migration classes.
@@ -558,7 +766,7 @@ module ActiveRecord
558
766
  revert { run(*migration_classes, direction: dir, revert: true) }
559
767
  else
560
768
  migration_classes.each do |migration_class|
561
- migration_class.new.exec_migration(@connection, dir)
769
+ migration_class.new.exec_migration(connection, dir)
562
770
  end
563
771
  end
564
772
  end
@@ -584,7 +792,7 @@ module ActiveRecord
584
792
  when :down then announce "reverting"
585
793
  end
586
794
 
587
- time = nil
795
+ time = nil
588
796
  ActiveRecord::Base.connection_pool.with_connection do |conn|
589
797
  time = Benchmark.measure do
590
798
  exec_migration(conn, direction)
@@ -612,7 +820,7 @@ module ActiveRecord
612
820
  @connection = nil
613
821
  end
614
822
 
615
- def write(text="")
823
+ def write(text = "")
616
824
  puts(text) if verbose
617
825
  end
618
826
 
@@ -622,7 +830,7 @@ module ActiveRecord
622
830
  write "== %s %s" % [text, "=" * length]
623
831
  end
624
832
 
625
- def say(message, subitem=false)
833
+ def say(message, subitem = false)
626
834
  write "#{subitem ? " ->" : "--"} #{message}"
627
835
  end
628
836
 
@@ -647,13 +855,14 @@ module ActiveRecord
647
855
  end
648
856
 
649
857
  def method_missing(method, *arguments, &block)
650
- arg_list = arguments.map{ |a| a.inspect } * ', '
858
+ arg_list = arguments.map(&:inspect) * ", "
651
859
 
652
860
  say_with_time "#{method}(#{arg_list})" do
653
- unless @connection.respond_to? :revert
861
+ unless connection.respond_to? :revert
654
862
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
655
863
  arguments[0] = proper_table_name(arguments.first, table_name_options)
656
- if [:rename_table, :add_foreign_key].include?(method)
864
+ if [:rename_table, :add_foreign_key].include?(method) ||
865
+ (method == :remove_foreign_key && !arguments.second.is_a?(Hash))
657
866
  arguments[1] = proper_table_name(arguments.second, table_name_options)
658
867
  end
659
868
  end
@@ -668,23 +877,25 @@ module ActiveRecord
668
877
 
669
878
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
670
879
 
671
- destination_migrations = ActiveRecord::Migrator.migrations(destination)
880
+ destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
672
881
  last = destination_migrations.last
673
882
  sources.each do |scope, path|
674
- source_migrations = ActiveRecord::Migrator.migrations(path)
883
+ source_migrations = ActiveRecord::MigrationContext.new(path).migrations
675
884
 
676
885
  source_migrations.each do |migration|
677
886
  source = File.binread(migration.filename)
678
887
  inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
679
- if /\A#.*\b(?:en)?coding:\s*\S+/ =~ source
888
+ magic_comments = "".dup
889
+ loop do
680
890
  # If we have a magic comment in the original migration,
681
891
  # insert our comment after the first newline(end of the magic comment line)
682
892
  # so the magic keep working.
683
893
  # Note that magic comments must be at the first line(except sh-bang).
684
- source[/\n/] = "\n#{inserted_comment}"
685
- else
686
- 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
687
897
  end
898
+ source = "#{magic_comments}#{inserted_comment}#{source}"
688
899
 
689
900
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
690
901
  if options[:on_skip] && duplicate.scope != scope.to_s
@@ -728,7 +939,9 @@ module ActiveRecord
728
939
  end
729
940
  end
730
941
 
731
- def table_name_options(config = ActiveRecord::Base)
942
+ # Builds a hash for use in ActiveRecord::Migration#proper_table_name using
943
+ # the Active Record object's table_name prefix and suffix
944
+ def table_name_options(config = ActiveRecord::Base) #:nodoc:
732
945
  {
733
946
  table_name_prefix: config.table_name_prefix,
734
947
  table_name_suffix: config.table_name_suffix
@@ -736,19 +949,18 @@ module ActiveRecord
736
949
  end
737
950
 
738
951
  private
739
- def execute_block
740
- if connection.respond_to? :execute_block
741
- super # use normal delegation to record the block
742
- else
743
- yield
952
+ def execute_block
953
+ if connection.respond_to? :execute_block
954
+ super # use normal delegation to record the block
955
+ else
956
+ yield
957
+ end
744
958
  end
745
- end
746
959
  end
747
960
 
748
961
  # MigrationProxy is used to defer loading of the actual migration classes
749
962
  # until they are needed
750
- class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
751
-
963
+ MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
752
964
  def initialize(name, version, filename, scope)
753
965
  super
754
966
  @migration = nil
@@ -774,7 +986,6 @@ module ActiveRecord
774
986
  require(File.expand_path(filename))
775
987
  name.constantize.new(name, version)
776
988
  end
777
-
778
989
  end
779
990
 
780
991
  class NullMigration < MigrationProxy #:nodoc:
@@ -787,131 +998,185 @@ module ActiveRecord
787
998
  end
788
999
  end
789
1000
 
790
- class Migrator#:nodoc:
791
- class << self
792
- attr_writer :migrations_paths
793
- alias :migrations_path= :migrations_paths=
794
-
795
- def migrate(migrations_paths, target_version = nil, &block)
796
- case
797
- when target_version.nil?
798
- up(migrations_paths, target_version, &block)
799
- when current_version == 0 && target_version == 0
800
- []
801
- when current_version > target_version
802
- down(migrations_paths, target_version, &block)
803
- else
804
- up(migrations_paths, target_version, &block)
805
- end
806
- end
1001
+ class MigrationContext # :nodoc:
1002
+ attr_reader :migrations_paths
807
1003
 
808
- def rollback(migrations_paths, steps=1)
809
- move(:down, migrations_paths, steps)
810
- end
1004
+ def initialize(migrations_paths)
1005
+ @migrations_paths = migrations_paths
1006
+ end
811
1007
 
812
- def forward(migrations_paths, steps=1)
813
- 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)
814
1018
  end
1019
+ end
1020
+
1021
+ def rollback(steps = 1)
1022
+ move(:down, steps)
1023
+ end
815
1024
 
816
- def up(migrations_paths, target_version = nil)
817
- migrations = migrations(migrations_paths)
818
- migrations.select! { |m| yield m } if block_given?
1025
+ def forward(steps = 1)
1026
+ move(:up, steps)
1027
+ end
819
1028
 
820
- 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
821
1034
  end
822
1035
 
823
- def down(migrations_paths, target_version = nil, &block)
824
- migrations = migrations(migrations_paths)
825
- migrations.select! { |m| yield m } if block_given?
1036
+ Migrator.new(:up, selected_migrations, target_version).migrate
1037
+ end
826
1038
 
827
- 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
828
1044
  end
829
1045
 
830
- def run(direction, migrations_paths, target_version)
831
- new(direction, migrations(migrations_paths), target_version).run
832
- end
1046
+ Migrator.new(:down, selected_migrations, target_version).migrate
1047
+ end
833
1048
 
834
- def open(migrations_paths)
835
- new(:up, migrations(migrations_paths), nil)
836
- end
1049
+ def run(direction, target_version)
1050
+ Migrator.new(direction, migrations, target_version).run
1051
+ end
837
1052
 
838
- def schema_migrations_table_name
839
- SchemaMigration.table_name
840
- end
1053
+ def open
1054
+ Migrator.new(:up, migrations, nil)
1055
+ end
841
1056
 
842
- def get_all_versions(connection = Base.connection)
843
- if connection.table_exists?(schema_migrations_table_name)
844
- SchemaMigration.all.map { |x| x.version.to_i }.sort
845
- else
846
- []
847
- end
1057
+ def get_all_versions
1058
+ if SchemaMigration.table_exists?
1059
+ SchemaMigration.all_versions.map(&:to_i)
1060
+ else
1061
+ []
848
1062
  end
1063
+ end
849
1064
 
850
- def current_version(connection = Base.connection)
851
- get_all_versions(connection).max || 0
852
- end
1065
+ def current_version
1066
+ get_all_versions.max || 0
1067
+ rescue ActiveRecord::NoDatabaseError
1068
+ end
853
1069
 
854
- def needs_migration?(connection = Base.connection)
855
- (migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
856
- end
1070
+ def needs_migration?
1071
+ (migrations.collect(&:version) - get_all_versions).size > 0
1072
+ end
857
1073
 
858
- def any_migrations?
859
- migrations(migrations_paths).any?
860
- end
1074
+ def any_migrations?
1075
+ migrations.any?
1076
+ end
861
1077
 
862
- def last_version
863
- last_migration.version
864
- end
1078
+ def last_migration #:nodoc:
1079
+ migrations.last || NullMigration.new
1080
+ end
865
1081
 
866
- def last_migration #:nodoc:
867
- migrations(migrations_paths).last || NullMigration.new
868
- end
1082
+ def parse_migration_filename(filename) # :nodoc:
1083
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1084
+ end
869
1085
 
870
- def migrations_paths
871
- @migrations_paths ||= ['db/migrate']
872
- # just to not break things if someone uses: migration_path = some_string
873
- Array(@migrations_paths)
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)
874
1094
  end
875
1095
 
876
- def migrations_path
877
- migrations_paths.first
1096
+ migrations.sort_by(&:version)
1097
+ end
1098
+
1099
+ def migrations_status
1100
+ db_list = ActiveRecord::SchemaMigration.normalized_versions
1101
+
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
1109
+
1110
+ db_list.map! do |version|
1111
+ ["up", version, "********** NO FILE **********"]
878
1112
  end
879
1113
 
880
- def migrations(paths)
881
- paths = Array(paths)
1114
+ (db_list + file_list).sort_by { |_, version, _| version }
1115
+ end
882
1116
 
883
- files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
1117
+ def migration_files
1118
+ paths = Array(migrations_paths)
1119
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1120
+ end
884
1121
 
885
- migrations = files.map do |file|
886
- version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
1122
+ def current_environment
1123
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1124
+ end
887
1125
 
888
- raise IllegalMigrationNameError.new(file) unless version
889
- version = version.to_i
890
- name = name.camelize
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?
1133
+
1134
+ environment = ActiveRecord::InternalMetadata[:environment]
1135
+ raise NoEnvironmentInSchemaError unless environment
1136
+ environment
1137
+ end
891
1138
 
892
- MigrationProxy.new(name, version, file, scope)
1139
+ private
1140
+ def move(direction, steps)
1141
+ migrator = Migrator.new(direction, migrations)
1142
+
1143
+ if current_version != 0 && !migrator.current_migration
1144
+ raise UnknownMigrationVersionError.new(current_version)
893
1145
  end
894
1146
 
895
- migrations.sort_by(&:version)
1147
+ start_index =
1148
+ if current_version == 0
1149
+ 0
1150
+ else
1151
+ migrator.migrations.index(migrator.current_migration)
1152
+ end
1153
+
1154
+ finish = migrator.migrations[start_index + steps]
1155
+ version = finish ? finish.version : 0
1156
+ send(direction, version)
896
1157
  end
1158
+ end
897
1159
 
898
- private
1160
+ class Migrator # :nodoc:
1161
+ class << self
1162
+ attr_accessor :migrations_paths
899
1163
 
900
- def move(direction, migrations_paths, steps)
901
- migrator = new(direction, migrations(migrations_paths))
902
- 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
903
1170
 
904
- if start_index
905
- finish = migrator.migrations[start_index + steps]
906
- version = finish ? finish.version : 0
907
- send(direction, migrations_paths, version)
908
- 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
909
1174
  end
910
1175
  end
911
1176
 
912
- def initialize(direction, migrations, target_version = nil)
913
- raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
1177
+ self.migrations_paths = ["db/migrate"]
914
1178
 
1179
+ def initialize(direction, migrations, target_version = nil)
915
1180
  @direction = direction
916
1181
  @target_version = target_version
917
1182
  @migrated_versions = nil
@@ -919,7 +1184,8 @@ module ActiveRecord
919
1184
 
920
1185
  validate(@migrations)
921
1186
 
922
- Base.connection.initialize_schema_migrations_table
1187
+ ActiveRecord::SchemaMigration.create_table
1188
+ ActiveRecord::InternalMetadata.create_table
923
1189
  end
924
1190
 
925
1191
  def current_version
@@ -932,32 +1198,18 @@ module ActiveRecord
932
1198
  alias :current :current_migration
933
1199
 
934
1200
  def run
935
- migration = migrations.detect { |m| m.version == @target_version }
936
- raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
937
- unless (up? && migrated.include?(migration.version.to_i)) || (down? && !migrated.include?(migration.version.to_i))
938
- begin
939
- execute_migration_in_transaction(migration, @direction)
940
- rescue => e
941
- canceled_msg = use_transaction?(migration) ? ", this migration was canceled" : ""
942
- raise StandardError, "An error has occurred#{canceled_msg}:\n\n#{e}", e.backtrace
943
- end
1201
+ if use_advisory_lock?
1202
+ with_advisory_lock { run_without_lock }
1203
+ else
1204
+ run_without_lock
944
1205
  end
945
1206
  end
946
1207
 
947
1208
  def migrate
948
- if !target && @target_version && @target_version > 0
949
- raise UnknownMigrationVersionError.new(@target_version)
950
- end
951
-
952
- runnable.each do |migration|
953
- Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
954
-
955
- begin
956
- execute_migration_in_transaction(migration, @direction)
957
- rescue => e
958
- canceled_msg = use_transaction?(migration) ? "this and " : ""
959
- raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
960
- end
1209
+ if use_advisory_lock?
1210
+ with_advisory_lock { migrate_without_lock }
1211
+ else
1212
+ migrate_without_lock
961
1213
  end
962
1214
  end
963
1215
 
@@ -982,70 +1234,145 @@ module ActiveRecord
982
1234
  end
983
1235
 
984
1236
  def migrated
985
- @migrated_versions ||= Set.new(self.class.get_all_versions)
1237
+ @migrated_versions || load_migrated
986
1238
  end
987
1239
 
988
- private
989
- def ran?(migration)
990
- migrated.include?(migration.version.to_i)
1240
+ def load_migrated
1241
+ @migrated_versions = Set.new(Base.connection.migration_context.get_all_versions)
991
1242
  end
992
1243
 
993
- def execute_migration_in_transaction(migration, direction)
994
- ddl_transaction(migration) do
995
- migration.migrate(direction)
996
- record_version_state_after_migrating(migration.version)
1244
+ private
1245
+
1246
+ # Used for running a specific migration.
1247
+ def run_without_lock
1248
+ migration = migrations.detect { |m| m.version == @target_version }
1249
+ raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1250
+ result = execute_migration_in_transaction(migration, @direction)
1251
+
1252
+ record_environment
1253
+ result
997
1254
  end
998
- end
999
1255
 
1000
- def target
1001
- migrations.detect { |m| m.version == @target_version }
1002
- end
1256
+ # Used for running multiple migrations up to or down to a certain value.
1257
+ def migrate_without_lock
1258
+ if invalid_target?
1259
+ raise UnknownMigrationVersionError.new(@target_version)
1260
+ end
1003
1261
 
1004
- def finish
1005
- migrations.index(target) || migrations.size - 1
1006
- end
1262
+ result = runnable.each do |migration|
1263
+ execute_migration_in_transaction(migration, @direction)
1264
+ end
1007
1265
 
1008
- def start
1009
- up? ? 0 : (migrations.index(current) || 0)
1010
- end
1266
+ record_environment
1267
+ result
1268
+ end
1011
1269
 
1012
- def validate(migrations)
1013
- name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
1014
- raise DuplicateMigrationNameError.new(name) if name
1270
+ # Stores the current environment in the database.
1271
+ def record_environment
1272
+ return if down?
1273
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Base.connection.migration_context.current_environment
1274
+ end
1015
1275
 
1016
- version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
1017
- raise DuplicateMigrationVersionError.new(version) if version
1018
- end
1276
+ def ran?(migration)
1277
+ migrated.include?(migration.version.to_i)
1278
+ end
1019
1279
 
1020
- def record_version_state_after_migrating(version)
1021
- if down?
1022
- migrated.delete(version)
1023
- ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
1024
- else
1025
- migrated << version
1026
- ActiveRecord::SchemaMigration.create!(:version => version.to_s)
1280
+ # Return true if a valid version is not provided.
1281
+ def invalid_target?
1282
+ @target_version && @target_version != 0 && !target
1027
1283
  end
1028
- end
1029
1284
 
1030
- def up?
1031
- @direction == :up
1032
- end
1285
+ def execute_migration_in_transaction(migration, direction)
1286
+ return if down? && !migrated.include?(migration.version.to_i)
1287
+ return if up? && migrated.include?(migration.version.to_i)
1033
1288
 
1034
- def down?
1035
- @direction == :down
1036
- end
1289
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1037
1290
 
1038
- # Wrap the migration in a transaction only if supported by the adapter.
1039
- def ddl_transaction(migration)
1040
- if use_transaction?(migration)
1041
- Base.transaction { yield }
1042
- else
1291
+ ddl_transaction(migration) do
1292
+ migration.migrate(direction)
1293
+ record_version_state_after_migrating(migration.version)
1294
+ end
1295
+ rescue => e
1296
+ msg = "An error has occurred, ".dup
1297
+ msg << "this and " if use_transaction?(migration)
1298
+ msg << "all later migrations canceled:\n\n#{e}"
1299
+ raise StandardError, msg, e.backtrace
1300
+ end
1301
+
1302
+ def target
1303
+ migrations.detect { |m| m.version == @target_version }
1304
+ end
1305
+
1306
+ def finish
1307
+ migrations.index(target) || migrations.size - 1
1308
+ end
1309
+
1310
+ def start
1311
+ up? ? 0 : (migrations.index(current) || 0)
1312
+ end
1313
+
1314
+ def validate(migrations)
1315
+ name, = migrations.group_by(&:name).find { |_, v| v.length > 1 }
1316
+ raise DuplicateMigrationNameError.new(name) if name
1317
+
1318
+ version, = migrations.group_by(&:version).find { |_, v| v.length > 1 }
1319
+ raise DuplicateMigrationVersionError.new(version) if version
1320
+ end
1321
+
1322
+ def record_version_state_after_migrating(version)
1323
+ if down?
1324
+ migrated.delete(version)
1325
+ ActiveRecord::SchemaMigration.where(version: version.to_s).delete_all
1326
+ else
1327
+ migrated << version
1328
+ ActiveRecord::SchemaMigration.create!(version: version.to_s)
1329
+ end
1330
+ end
1331
+
1332
+ def up?
1333
+ @direction == :up
1334
+ end
1335
+
1336
+ def down?
1337
+ @direction == :down
1338
+ end
1339
+
1340
+ # Wrap the migration in a transaction only if supported by the adapter.
1341
+ def ddl_transaction(migration)
1342
+ if use_transaction?(migration)
1343
+ Base.transaction { yield }
1344
+ else
1345
+ yield
1346
+ end
1347
+ end
1348
+
1349
+ def use_transaction?(migration)
1350
+ !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1351
+ end
1352
+
1353
+ def use_advisory_lock?
1354
+ Base.connection.supports_advisory_locks?
1355
+ end
1356
+
1357
+ def with_advisory_lock
1358
+ lock_id = generate_migrator_advisory_lock_id
1359
+ connection = Base.connection
1360
+ got_lock = connection.get_advisory_lock(lock_id)
1361
+ raise ConcurrentMigrationError unless got_lock
1362
+ load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1043
1363
  yield
1364
+ ensure
1365
+ if got_lock && !connection.release_advisory_lock(lock_id)
1366
+ raise ConcurrentMigrationError.new(
1367
+ ConcurrentMigrationError::RELEASE_LOCK_FAILED_MESSAGE
1368
+ )
1369
+ end
1044
1370
  end
1045
- end
1046
1371
 
1047
- def use_transaction?(migration)
1048
- !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1049
- end
1372
+ MIGRATOR_SALT = 2053462845
1373
+ def generate_migrator_advisory_lock_id
1374
+ db_name_hash = Zlib.crc32(Base.connection.current_database)
1375
+ MIGRATOR_SALT * db_name_hash
1376
+ end
1050
1377
  end
1051
1378
  end