activerecord 4.2.9 → 5.2.8

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 +614 -1572
  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 +263 -249
  8. data/lib/active_record/association_relation.rb +11 -6
  9. data/lib/active_record/associations/alias_tracker.rb +29 -35
  10. data/lib/active_record/associations/association.rb +77 -43
  11. data/lib/active_record/associations/association_scope.rb +106 -133
  12. data/lib/active_record/associations/belongs_to_association.rb +52 -41
  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 +9 -22
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +42 -35
  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 +139 -280
  22. data/lib/active_record/associations/collection_proxy.rb +231 -133
  23. data/lib/active_record/associations/foreign_association.rb +3 -1
  24. data/lib/active_record/associations/has_many_association.rb +34 -89
  25. data/lib/active_record/associations/has_many_through_association.rb +49 -76
  26. data/lib/active_record/associations/has_one_association.rb +38 -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 -89
  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 +133 -159
  32. data/lib/active_record/associations/preloader/association.rb +85 -120
  33. data/lib/active_record/associations/preloader/through_association.rb +85 -74
  34. data/lib/active_record/associations/preloader.rb +81 -91
  35. data/lib/active_record/associations/singular_association.rb +27 -34
  36. data/lib/active_record/associations/through_association.rb +38 -18
  37. data/lib/active_record/associations.rb +1732 -1597
  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 +10 -8
  41. data/lib/active_record/attribute_methods/dirty.rb +94 -135
  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 +58 -36
  47. data/lib/active_record/attribute_methods/write.rb +30 -45
  48. data/lib/active_record/attribute_methods.rb +166 -109
  49. data/lib/active_record/attributes.rb +201 -82
  50. data/lib/active_record/autosave_association.rb +94 -36
  51. data/lib/active_record/base.rb +57 -44
  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 +24 -12
  55. data/lib/active_record/collection_cache_key.rb +53 -0
  56. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +712 -290
  57. data/lib/active_record/connection_adapters/abstract/database_limits.rb +10 -5
  58. data/lib/active_record/connection_adapters/abstract/database_statements.rb +237 -90
  59. data/lib/active_record/connection_adapters/abstract/query_cache.rb +71 -21
  60. data/lib/active_record/connection_adapters/abstract/quoting.rb +118 -52
  61. data/lib/active_record/connection_adapters/abstract/savepoints.rb +5 -3
  62. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +67 -46
  63. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +318 -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 +570 -228
  66. data/lib/active_record/connection_adapters/abstract/transaction.rb +138 -70
  67. data/lib/active_record/connection_adapters/abstract_adapter.rb +325 -202
  68. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +542 -593
  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 +41 -188
  82. data/lib/active_record/connection_adapters/postgresql/column.rb +35 -11
  83. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +45 -114
  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 -58
  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 +4 -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 -22
  92. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +3 -1
  93. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +5 -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 -5
  103. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +55 -53
  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 +462 -284
  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 +432 -323
  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 -308
  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 +178 -198
  129. data/lib/active_record/counter_cache.rb +79 -36
  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 +135 -88
  133. data/lib/active_record/errors.rb +179 -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 +10 -5
  137. data/lib/active_record/fixture_set/file.rb +35 -9
  138. data/lib/active_record/fixtures.rb +188 -132
  139. data/lib/active_record/gem_version.rb +4 -2
  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 +21 -3
  144. data/lib/active_record/locale/en.yml +3 -2
  145. data/lib/active_record/locking/optimistic.rb +88 -96
  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 +581 -282
  152. data/lib/active_record/model_schema.rb +290 -111
  153. data/lib/active_record/nested_attributes.rb +264 -222
  154. data/lib/active_record/no_touching.rb +7 -1
  155. data/lib/active_record/null_relation.rb +24 -37
  156. data/lib/active_record/persistence.rb +347 -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 +94 -32
  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 +149 -156
  163. data/lib/active_record/readonly_attributes.rb +5 -4
  164. data/lib/active_record/reflection.rb +414 -267
  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 +256 -248
  168. data/lib/active_record/relation/delegation.rb +67 -60
  169. data/lib/active_record/relation/finder_methods.rb +288 -239
  170. data/lib/active_record/relation/from_clause.rb +26 -0
  171. data/lib/active_record/relation/merger.rb +86 -86
  172. data/lib/active_record/relation/predicate_builder/array_handler.rb +24 -24
  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 +116 -119
  180. data/lib/active_record/relation/query_attribute.rb +45 -0
  181. data/lib/active_record/relation/query_methods.rb +448 -393
  182. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  183. data/lib/active_record/relation/spawn_methods.rb +11 -13
  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 -340
  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 -16
  193. data/lib/active_record/scoping/default.rb +102 -85
  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 +134 -96
  203. data/lib/active_record/tasks/mysql_database_tasks.rb +56 -100
  204. data/lib/active_record/tasks/postgresql_database_tasks.rb +83 -41
  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 +199 -124
  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 -45
  212. data/lib/active_record/type/date_time.rb +4 -49
  213. data/lib/active_record/type/decimal_without_scale.rb +6 -2
  214. data/lib/active_record/type/hash_lookup_type_map.rb +5 -3
  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 +24 -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 +40 -41
  231. data/lib/active_record/validations.rb +38 -35
  232. data/lib/active_record/version.rb +3 -1
  233. data/lib/active_record.rb +34 -22
  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 -3
  238. data/lib/rails/generators/active_record/migration/templates/{migration.rb → migration.rb.tt} +8 -1
  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/model/templates/{module.rb → module.rb.tt} +0 -0
  243. data/lib/rails/generators/active_record.rb +7 -5
  244. metadata +72 -50
  245. data/lib/active_record/associations/preloader/belongs_to.rb +0 -17
  246. data/lib/active_record/associations/preloader/collection_association.rb +0 -24
  247. data/lib/active_record/associations/preloader/has_many.rb +0 -17
  248. data/lib/active_record/associations/preloader/has_many_through.rb +0 -19
  249. data/lib/active_record/associations/preloader/has_one.rb +0 -23
  250. data/lib/active_record/associations/preloader/has_one_through.rb +0 -9
  251. data/lib/active_record/associations/preloader/singular_association.rb +0 -21
  252. data/lib/active_record/attribute.rb +0 -163
  253. data/lib/active_record/attribute_set/builder.rb +0 -106
  254. data/lib/active_record/attribute_set.rb +0 -81
  255. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -491
  256. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  257. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  258. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  259. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +0 -35
  260. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  261. data/lib/active_record/railties/jdbcmysql_error.rb +0 -16
  262. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  263. data/lib/active_record/type/big_integer.rb +0 -13
  264. data/lib/active_record/type/binary.rb +0 -50
  265. data/lib/active_record/type/boolean.rb +0 -31
  266. data/lib/active_record/type/decimal.rb +0 -64
  267. data/lib/active_record/type/decorator.rb +0 -14
  268. data/lib/active_record/type/float.rb +0 -19
  269. data/lib/active_record/type/integer.rb +0 -59
  270. data/lib/active_record/type/mutable.rb +0 -16
  271. data/lib/active_record/type/numeric.rb +0 -36
  272. data/lib/active_record/type/string.rb +0 -40
  273. data/lib/active_record/type/time_value.rb +0 -38
  274. data/lib/active_record/type/value.rb +0 -110
@@ -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
152
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n bin/rails db:environment:set"
42
153
  if defined?(Rails.env)
43
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate RAILS_ENV=#{::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:
@@ -314,7 +474,7 @@ module ActiveRecord
314
474
  # To define a reversible migration, define the +change+ method in your
315
475
  # migration like this:
316
476
  #
317
- # class TenderloveMigration < ActiveRecord::Migration
477
+ # class TenderloveMigration < ActiveRecord::Migration[5.0]
318
478
  # def change
319
479
  # create_table(:horses) do |t|
320
480
  # t.column :content, :text
@@ -344,7 +504,7 @@ module ActiveRecord
344
504
  # can't execute inside a transaction though, and for these situations
345
505
  # you can turn the automatic transactions off.
346
506
  #
347
- # class ChangeEnum < ActiveRecord::Migration
507
+ # class ChangeEnum < ActiveRecord::Migration[5.0]
348
508
  # disable_ddl_transaction!
349
509
  #
350
510
  # def up
@@ -355,11 +515,35 @@ module ActiveRecord
355
515
  # Remember that you can still open your own transactions, even if you
356
516
  # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
357
517
  class Migration
358
- autoload :CommandRecorder, 'active_record/migration/command_recorder'
518
+ autoload :CommandRecorder, "active_record/migration/command_recorder"
519
+ autoload :Compatibility, "active_record/migration/compatibility"
359
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:
360
544
 
361
545
  # This class is used to verify that all migrations have been run before
362
- # 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
363
547
  class CheckPending
364
548
  def initialize(app)
365
549
  @app = app
@@ -367,38 +551,42 @@ module ActiveRecord
367
551
  end
368
552
 
369
553
  def call(env)
370
- if connection.supports_migrations?
371
- mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
372
- if @last_check < mtime
373
- ActiveRecord::Migration.check_pending!(connection)
374
- @last_check = mtime
375
- 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
376
558
  end
377
559
  @app.call(env)
378
560
  end
379
561
 
380
562
  private
381
563
 
382
- def connection
383
- ActiveRecord::Base.connection
384
- end
564
+ def connection
565
+ ActiveRecord::Base.connection
566
+ end
385
567
  end
386
568
 
387
569
  class << self
388
570
  attr_accessor :delegate # :nodoc:
389
571
  attr_accessor :disable_ddl_transaction # :nodoc:
390
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.
391
578
  def check_pending!(connection = Base.connection)
392
- raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
579
+ raise ActiveRecord::PendingMigrationError if connection.migration_context.needs_migration?
393
580
  end
394
581
 
395
582
  def load_schema_if_pending!
396
- if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
397
- # Roundrip to Rake to allow plugins to hook into database initialization.
398
- 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
399
587
  current_config = Base.connection_config
400
588
  Base.clear_all_connections!
401
- system("bin/rake db:test:prepare")
589
+ system("bin/rails db:test:prepare")
402
590
  # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
403
591
  Base.establish_connection(current_config)
404
592
  end
@@ -413,7 +601,7 @@ module ActiveRecord
413
601
  end
414
602
 
415
603
  def method_missing(name, *args, &block) # :nodoc:
416
- (delegate || superclass.delegate).send(name, *args, &block)
604
+ nearest_delegate.send(name, *args, &block)
417
605
  end
418
606
 
419
607
  def migrate(direction)
@@ -453,7 +641,7 @@ module ActiveRecord
453
641
  # and create the table 'apples' on the way up, and the reverse
454
642
  # on the way down.
455
643
  #
456
- # class FixTLMigration < ActiveRecord::Migration
644
+ # class FixTLMigration < ActiveRecord::Migration[5.0]
457
645
  # def change
458
646
  # revert do
459
647
  # create_table(:horses) do |t|
@@ -470,9 +658,9 @@ module ActiveRecord
470
658
  # Or equivalently, if +TenderloveMigration+ is defined as in the
471
659
  # documentation for Migration:
472
660
  #
473
- # require_relative '2012121212_tenderlove_migration'
661
+ # require_relative '20121212123456_tenderlove_migration'
474
662
  #
475
- # class FixupTLMigration < ActiveRecord::Migration
663
+ # class FixupTLMigration < ActiveRecord::Migration[5.0]
476
664
  # def change
477
665
  # revert TenderloveMigration
478
666
  #
@@ -486,13 +674,13 @@ module ActiveRecord
486
674
  def revert(*migration_classes)
487
675
  run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
488
676
  if block_given?
489
- if @connection.respond_to? :revert
490
- @connection.revert { yield }
677
+ if connection.respond_to? :revert
678
+ connection.revert { yield }
491
679
  else
492
- recorder = CommandRecorder.new(@connection)
680
+ recorder = CommandRecorder.new(connection)
493
681
  @connection = recorder
494
682
  suppress_messages do
495
- @connection.revert { yield }
683
+ connection.revert { yield }
496
684
  end
497
685
  @connection = recorder.delegate
498
686
  recorder.commands.each do |cmd, args, block|
@@ -503,10 +691,10 @@ module ActiveRecord
503
691
  end
504
692
 
505
693
  def reverting?
506
- @connection.respond_to?(:reverting) && @connection.reverting
694
+ connection.respond_to?(:reverting) && connection.reverting
507
695
  end
508
696
 
509
- class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
697
+ ReversibleBlockHelper = Struct.new(:reverting) do # :nodoc:
510
698
  def up
511
699
  yield unless reverting
512
700
  end
@@ -525,7 +713,7 @@ module ActiveRecord
525
713
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
526
714
  # even when migrating down:
527
715
  #
528
- # class SplitNameMigration < ActiveRecord::Migration
716
+ # class SplitNameMigration < ActiveRecord::Migration[5.0]
529
717
  # def change
530
718
  # add_column :users, :first_name, :string
531
719
  # add_column :users, :last_name, :string
@@ -544,7 +732,25 @@ module ActiveRecord
544
732
  # end
545
733
  def reversible
546
734
  helper = ReversibleBlockHelper.new(reverting?)
547
- 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?
548
754
  end
549
755
 
550
756
  # Runs the given migration classes.
@@ -560,7 +766,7 @@ module ActiveRecord
560
766
  revert { run(*migration_classes, direction: dir, revert: true) }
561
767
  else
562
768
  migration_classes.each do |migration_class|
563
- migration_class.new.exec_migration(@connection, dir)
769
+ migration_class.new.exec_migration(connection, dir)
564
770
  end
565
771
  end
566
772
  end
@@ -586,7 +792,7 @@ module ActiveRecord
586
792
  when :down then announce "reverting"
587
793
  end
588
794
 
589
- time = nil
795
+ time = nil
590
796
  ActiveRecord::Base.connection_pool.with_connection do |conn|
591
797
  time = Benchmark.measure do
592
798
  exec_migration(conn, direction)
@@ -614,7 +820,7 @@ module ActiveRecord
614
820
  @connection = nil
615
821
  end
616
822
 
617
- def write(text="")
823
+ def write(text = "")
618
824
  puts(text) if verbose
619
825
  end
620
826
 
@@ -624,7 +830,7 @@ module ActiveRecord
624
830
  write "== %s %s" % [text, "=" * length]
625
831
  end
626
832
 
627
- def say(message, subitem=false)
833
+ def say(message, subitem = false)
628
834
  write "#{subitem ? " ->" : "--"} #{message}"
629
835
  end
630
836
 
@@ -649,10 +855,10 @@ module ActiveRecord
649
855
  end
650
856
 
651
857
  def method_missing(method, *arguments, &block)
652
- arg_list = arguments.map{ |a| a.inspect } * ', '
858
+ arg_list = arguments.map(&:inspect) * ", "
653
859
 
654
860
  say_with_time "#{method}(#{arg_list})" do
655
- unless @connection.respond_to? :revert
861
+ unless connection.respond_to? :revert
656
862
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
657
863
  arguments[0] = proper_table_name(arguments.first, table_name_options)
658
864
  if [:rename_table, :add_foreign_key].include?(method) ||
@@ -671,23 +877,25 @@ module ActiveRecord
671
877
 
672
878
  FileUtils.mkdir_p(destination) unless File.exist?(destination)
673
879
 
674
- destination_migrations = ActiveRecord::Migrator.migrations(destination)
880
+ destination_migrations = ActiveRecord::MigrationContext.new(destination).migrations
675
881
  last = destination_migrations.last
676
882
  sources.each do |scope, path|
677
- source_migrations = ActiveRecord::Migrator.migrations(path)
883
+ source_migrations = ActiveRecord::MigrationContext.new(path).migrations
678
884
 
679
885
  source_migrations.each do |migration|
680
886
  source = File.binread(migration.filename)
681
887
  inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
682
- if /\A#.*\b(?:en)?coding:\s*\S+/ =~ source
888
+ magic_comments = "".dup
889
+ loop do
683
890
  # If we have a magic comment in the original migration,
684
891
  # insert our comment after the first newline(end of the magic comment line)
685
892
  # so the magic keep working.
686
893
  # Note that magic comments must be at the first line(except sh-bang).
687
- source[/\n/] = "\n#{inserted_comment}"
688
- else
689
- 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
690
897
  end
898
+ source = "#{magic_comments}#{inserted_comment}#{source}"
691
899
 
692
900
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
693
901
  if options[:on_skip] && duplicate.scope != scope.to_s
@@ -731,7 +939,9 @@ module ActiveRecord
731
939
  end
732
940
  end
733
941
 
734
- 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:
735
945
  {
736
946
  table_name_prefix: config.table_name_prefix,
737
947
  table_name_suffix: config.table_name_suffix
@@ -739,19 +949,18 @@ module ActiveRecord
739
949
  end
740
950
 
741
951
  private
742
- def execute_block
743
- if connection.respond_to? :execute_block
744
- super # use normal delegation to record the block
745
- else
746
- 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
747
958
  end
748
- end
749
959
  end
750
960
 
751
961
  # MigrationProxy is used to defer loading of the actual migration classes
752
962
  # until they are needed
753
- class MigrationProxy < Struct.new(:name, :version, :filename, :scope)
754
-
963
+ MigrationProxy = Struct.new(:name, :version, :filename, :scope) do
755
964
  def initialize(name, version, filename, scope)
756
965
  super
757
966
  @migration = nil
@@ -777,7 +986,6 @@ module ActiveRecord
777
986
  require(File.expand_path(filename))
778
987
  name.constantize.new(name, version)
779
988
  end
780
-
781
989
  end
782
990
 
783
991
  class NullMigration < MigrationProxy #:nodoc:
@@ -790,156 +998,185 @@ module ActiveRecord
790
998
  end
791
999
  end
792
1000
 
793
- class Migrator#:nodoc:
794
- class << self
795
- attr_writer :migrations_paths
796
- alias :migrations_path= :migrations_paths=
797
-
798
- def migrate(migrations_paths, target_version = nil, &block)
799
- case
800
- when target_version.nil?
801
- up(migrations_paths, target_version, &block)
802
- when current_version == 0 && target_version == 0
803
- []
804
- when current_version > target_version
805
- down(migrations_paths, target_version, &block)
806
- else
807
- up(migrations_paths, target_version, &block)
808
- end
809
- end
1001
+ class MigrationContext # :nodoc:
1002
+ attr_reader :migrations_paths
810
1003
 
811
- def rollback(migrations_paths, steps=1)
812
- move(:down, migrations_paths, steps)
813
- end
1004
+ def initialize(migrations_paths)
1005
+ @migrations_paths = migrations_paths
1006
+ end
814
1007
 
815
- def forward(migrations_paths, steps=1)
816
- 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)
817
1018
  end
1019
+ end
1020
+
1021
+ def rollback(steps = 1)
1022
+ move(:down, steps)
1023
+ end
818
1024
 
819
- def up(migrations_paths, target_version = nil)
820
- migrations = migrations(migrations_paths)
821
- migrations.select! { |m| yield m } if block_given?
1025
+ def forward(steps = 1)
1026
+ move(:up, steps)
1027
+ end
822
1028
 
823
- 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
824
1034
  end
825
1035
 
826
- def down(migrations_paths, target_version = nil, &block)
827
- migrations = migrations(migrations_paths)
828
- migrations.select! { |m| yield m } if block_given?
1036
+ Migrator.new(:up, selected_migrations, target_version).migrate
1037
+ end
829
1038
 
830
- 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
831
1044
  end
832
1045
 
833
- def run(direction, migrations_paths, target_version)
834
- new(direction, migrations(migrations_paths), target_version).run
835
- end
1046
+ Migrator.new(:down, selected_migrations, target_version).migrate
1047
+ end
836
1048
 
837
- def open(migrations_paths)
838
- new(:up, migrations(migrations_paths), nil)
839
- end
1049
+ def run(direction, target_version)
1050
+ Migrator.new(direction, migrations, target_version).run
1051
+ end
840
1052
 
841
- def schema_migrations_table_name
842
- SchemaMigration.table_name
843
- end
1053
+ def open
1054
+ Migrator.new(:up, migrations, nil)
1055
+ end
844
1056
 
845
- def get_all_versions(connection = Base.connection)
846
- if connection.table_exists?(schema_migrations_table_name)
847
- SchemaMigration.all.map { |x| x.version.to_i }.sort
848
- else
849
- []
850
- end
1057
+ def get_all_versions
1058
+ if SchemaMigration.table_exists?
1059
+ SchemaMigration.all_versions.map(&:to_i)
1060
+ else
1061
+ []
851
1062
  end
1063
+ end
852
1064
 
853
- def current_version(connection = Base.connection)
854
- get_all_versions(connection).max || 0
855
- end
1065
+ def current_version
1066
+ get_all_versions.max || 0
1067
+ rescue ActiveRecord::NoDatabaseError
1068
+ end
856
1069
 
857
- def needs_migration?(connection = Base.connection)
858
- (migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
859
- end
1070
+ def needs_migration?
1071
+ (migrations.collect(&:version) - get_all_versions).size > 0
1072
+ end
860
1073
 
861
- def any_migrations?
862
- migrations(migrations_paths).any?
863
- end
1074
+ def any_migrations?
1075
+ migrations.any?
1076
+ end
864
1077
 
865
- def last_version
866
- last_migration.version
867
- end
1078
+ def last_migration #:nodoc:
1079
+ migrations.last || NullMigration.new
1080
+ end
868
1081
 
869
- def last_migration #:nodoc:
870
- migrations(migrations_paths).last || NullMigration.new
871
- end
1082
+ def parse_migration_filename(filename) # :nodoc:
1083
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1084
+ end
872
1085
 
873
- def migrations_paths
874
- @migrations_paths ||= ['db/migrate']
875
- # just to not break things if someone uses: migration_path = some_string
876
- Array(@migrations_paths)
877
- end
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
878
1092
 
879
- def migrations_path
880
- migrations_paths.first
1093
+ MigrationProxy.new(name, version, file, scope)
881
1094
  end
882
1095
 
883
- def parse_migration_filename(filename) # :nodoc:
884
- File.basename(filename).scan(/\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).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 **********"]
885
1112
  end
886
1113
 
887
- def migrations(paths)
888
- paths = Array(paths)
1114
+ (db_list + file_list).sort_by { |_, version, _| version }
1115
+ end
889
1116
 
890
- migrations = migration_files(paths).map do |file|
891
- version, name, scope = parse_migration_filename(file)
892
- raise IllegalMigrationNameError.new(file) unless version
893
- version = version.to_i
894
- name = name.camelize
1117
+ def migration_files
1118
+ paths = Array(migrations_paths)
1119
+ Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
1120
+ end
895
1121
 
896
- MigrationProxy.new(name, version, file, scope)
897
- end
1122
+ def current_environment
1123
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1124
+ end
898
1125
 
899
- migrations.sort_by(&:version)
900
- end
1126
+ def protected_environment?
1127
+ ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1128
+ end
901
1129
 
902
- def migrations_status(paths)
903
- paths = Array(paths)
1130
+ def last_stored_environment
1131
+ return nil if current_version == 0
1132
+ raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
904
1133
 
905
- db_list = ActiveRecord::SchemaMigration.normalized_versions
1134
+ environment = ActiveRecord::InternalMetadata[:environment]
1135
+ raise NoEnvironmentInSchemaError unless environment
1136
+ environment
1137
+ end
906
1138
 
907
- file_list = migration_files(paths).map do |file|
908
- version, name, scope = parse_migration_filename(file)
909
- raise IllegalMigrationNameError.new(file) unless version
910
- version = ActiveRecord::SchemaMigration.normalize_migration_number(version)
911
- status = db_list.delete(version) ? "up" : "down"
912
- [status, version, (name + scope).humanize]
913
- end.compact
1139
+ private
1140
+ def move(direction, steps)
1141
+ migrator = Migrator.new(direction, migrations)
914
1142
 
915
- db_list.map! do |version|
916
- ["up", version, "********** NO FILE **********"]
1143
+ if current_version != 0 && !migrator.current_migration
1144
+ raise UnknownMigrationVersionError.new(current_version)
917
1145
  end
918
1146
 
919
- (db_list + file_list).sort_by { |_, version, _| version }
920
- end
1147
+ start_index =
1148
+ if current_version == 0
1149
+ 0
1150
+ else
1151
+ migrator.migrations.index(migrator.current_migration)
1152
+ end
921
1153
 
922
- def migration_files(paths)
923
- 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)
924
1157
  end
1158
+ end
925
1159
 
926
- private
1160
+ class Migrator # :nodoc:
1161
+ class << self
1162
+ attr_accessor :migrations_paths
927
1163
 
928
- def move(direction, migrations_paths, steps)
929
- migrator = new(direction, migrations(migrations_paths))
930
- 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
931
1170
 
932
- if start_index
933
- finish = migrator.migrations[start_index + steps]
934
- version = finish ? finish.version : 0
935
- send(direction, migrations_paths, version)
936
- 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
937
1174
  end
938
1175
  end
939
1176
 
940
- def initialize(direction, migrations, target_version = nil)
941
- raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
1177
+ self.migrations_paths = ["db/migrate"]
942
1178
 
1179
+ def initialize(direction, migrations, target_version = nil)
943
1180
  @direction = direction
944
1181
  @target_version = target_version
945
1182
  @migrated_versions = nil
@@ -947,7 +1184,8 @@ module ActiveRecord
947
1184
 
948
1185
  validate(@migrations)
949
1186
 
950
- Base.connection.initialize_schema_migrations_table
1187
+ ActiveRecord::SchemaMigration.create_table
1188
+ ActiveRecord::InternalMetadata.create_table
951
1189
  end
952
1190
 
953
1191
  def current_version
@@ -960,32 +1198,18 @@ module ActiveRecord
960
1198
  alias :current :current_migration
961
1199
 
962
1200
  def run
963
- migration = migrations.detect { |m| m.version == @target_version }
964
- raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
965
- unless (up? && migrated.include?(migration.version.to_i)) || (down? && !migrated.include?(migration.version.to_i))
966
- begin
967
- execute_migration_in_transaction(migration, @direction)
968
- rescue => e
969
- canceled_msg = use_transaction?(migration) ? ", this migration was canceled" : ""
970
- raise StandardError, "An error has occurred#{canceled_msg}:\n\n#{e}", e.backtrace
971
- end
1201
+ if use_advisory_lock?
1202
+ with_advisory_lock { run_without_lock }
1203
+ else
1204
+ run_without_lock
972
1205
  end
973
1206
  end
974
1207
 
975
1208
  def migrate
976
- if !target && @target_version && @target_version > 0
977
- raise UnknownMigrationVersionError.new(@target_version)
978
- end
979
-
980
- runnable.each do |migration|
981
- Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
982
-
983
- begin
984
- execute_migration_in_transaction(migration, @direction)
985
- rescue => e
986
- canceled_msg = use_transaction?(migration) ? "this and " : ""
987
- raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
988
- end
1209
+ if use_advisory_lock?
1210
+ with_advisory_lock { migrate_without_lock }
1211
+ else
1212
+ migrate_without_lock
989
1213
  end
990
1214
  end
991
1215
 
@@ -1010,70 +1234,145 @@ module ActiveRecord
1010
1234
  end
1011
1235
 
1012
1236
  def migrated
1013
- @migrated_versions ||= Set.new(self.class.get_all_versions)
1237
+ @migrated_versions || load_migrated
1014
1238
  end
1015
1239
 
1016
- private
1017
- def ran?(migration)
1018
- migrated.include?(migration.version.to_i)
1240
+ def load_migrated
1241
+ @migrated_versions = Set.new(Base.connection.migration_context.get_all_versions)
1019
1242
  end
1020
1243
 
1021
- def execute_migration_in_transaction(migration, direction)
1022
- ddl_transaction(migration) do
1023
- migration.migrate(direction)
1024
- 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
1025
1254
  end
1026
- end
1027
1255
 
1028
- def target
1029
- migrations.detect { |m| m.version == @target_version }
1030
- 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
1031
1261
 
1032
- def finish
1033
- migrations.index(target) || migrations.size - 1
1034
- end
1262
+ result = runnable.each do |migration|
1263
+ execute_migration_in_transaction(migration, @direction)
1264
+ end
1035
1265
 
1036
- def start
1037
- up? ? 0 : (migrations.index(current) || 0)
1038
- end
1266
+ record_environment
1267
+ result
1268
+ end
1039
1269
 
1040
- def validate(migrations)
1041
- name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
1042
- 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
1043
1275
 
1044
- version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
1045
- raise DuplicateMigrationVersionError.new(version) if version
1046
- end
1276
+ def ran?(migration)
1277
+ migrated.include?(migration.version.to_i)
1278
+ end
1047
1279
 
1048
- def record_version_state_after_migrating(version)
1049
- if down?
1050
- migrated.delete(version)
1051
- ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
1052
- else
1053
- migrated << version
1054
- 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
1055
1283
  end
1056
- end
1057
1284
 
1058
- def up?
1059
- @direction == :up
1060
- 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)
1061
1288
 
1062
- def down?
1063
- @direction == :down
1064
- end
1289
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1065
1290
 
1066
- # Wrap the migration in a transaction only if supported by the adapter.
1067
- def ddl_transaction(migration)
1068
- if use_transaction?(migration)
1069
- Base.transaction { yield }
1070
- 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
1071
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
1072
1370
  end
1073
- end
1074
1371
 
1075
- def use_transaction?(migration)
1076
- !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1077
- 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
1078
1377
  end
1079
1378
  end