activerecord 3.2.19 → 5.0.0

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

Potentially problematic release.


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

Files changed (264) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1715 -604
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +40 -45
  5. data/examples/performance.rb +33 -22
  6. data/examples/simple.rb +3 -4
  7. data/lib/active_record/aggregations.rb +76 -51
  8. data/lib/active_record/association_relation.rb +35 -0
  9. data/lib/active_record/associations/alias_tracker.rb +54 -40
  10. data/lib/active_record/associations/association.rb +76 -56
  11. data/lib/active_record/associations/association_scope.rb +125 -93
  12. data/lib/active_record/associations/belongs_to_association.rb +57 -28
  13. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +7 -2
  14. data/lib/active_record/associations/builder/association.rb +120 -32
  15. data/lib/active_record/associations/builder/belongs_to.rb +115 -62
  16. data/lib/active_record/associations/builder/collection_association.rb +61 -53
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +117 -43
  18. data/lib/active_record/associations/builder/has_many.rb +9 -65
  19. data/lib/active_record/associations/builder/has_one.rb +18 -52
  20. data/lib/active_record/associations/builder/singular_association.rb +18 -19
  21. data/lib/active_record/associations/collection_association.rb +268 -186
  22. data/lib/active_record/associations/collection_proxy.rb +1003 -63
  23. data/lib/active_record/associations/foreign_association.rb +11 -0
  24. data/lib/active_record/associations/has_many_association.rb +81 -41
  25. data/lib/active_record/associations/has_many_through_association.rb +76 -55
  26. data/lib/active_record/associations/has_one_association.rb +51 -21
  27. data/lib/active_record/associations/has_one_through_association.rb +1 -1
  28. data/lib/active_record/associations/join_dependency/join_association.rb +83 -108
  29. data/lib/active_record/associations/join_dependency/join_base.rb +7 -9
  30. data/lib/active_record/associations/join_dependency/join_part.rb +30 -37
  31. data/lib/active_record/associations/join_dependency.rb +239 -155
  32. data/lib/active_record/associations/preloader/association.rb +97 -62
  33. data/lib/active_record/associations/preloader/collection_association.rb +2 -8
  34. data/lib/active_record/associations/preloader/has_many_through.rb +7 -3
  35. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  36. data/lib/active_record/associations/preloader/singular_association.rb +3 -3
  37. data/lib/active_record/associations/preloader/through_association.rb +75 -33
  38. data/lib/active_record/associations/preloader.rb +111 -79
  39. data/lib/active_record/associations/singular_association.rb +35 -13
  40. data/lib/active_record/associations/through_association.rb +41 -19
  41. data/lib/active_record/associations.rb +727 -501
  42. data/lib/active_record/attribute/user_provided_default.rb +28 -0
  43. data/lib/active_record/attribute.rb +213 -0
  44. data/lib/active_record/attribute_assignment.rb +32 -162
  45. data/lib/active_record/attribute_decorators.rb +67 -0
  46. data/lib/active_record/attribute_methods/before_type_cast.rb +52 -7
  47. data/lib/active_record/attribute_methods/dirty.rb +101 -61
  48. data/lib/active_record/attribute_methods/primary_key.rb +50 -36
  49. data/lib/active_record/attribute_methods/query.rb +7 -6
  50. data/lib/active_record/attribute_methods/read.rb +56 -117
  51. data/lib/active_record/attribute_methods/serialization.rb +43 -96
  52. data/lib/active_record/attribute_methods/time_zone_conversion.rb +93 -42
  53. data/lib/active_record/attribute_methods/write.rb +34 -45
  54. data/lib/active_record/attribute_methods.rb +333 -144
  55. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  56. data/lib/active_record/attribute_set/builder.rb +108 -0
  57. data/lib/active_record/attribute_set.rb +108 -0
  58. data/lib/active_record/attributes.rb +265 -0
  59. data/lib/active_record/autosave_association.rb +285 -223
  60. data/lib/active_record/base.rb +95 -490
  61. data/lib/active_record/callbacks.rb +95 -61
  62. data/lib/active_record/coders/json.rb +13 -0
  63. data/lib/active_record/coders/yaml_column.rb +28 -19
  64. data/lib/active_record/collection_cache_key.rb +40 -0
  65. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +724 -277
  66. data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
  67. data/lib/active_record/connection_adapters/abstract/database_statements.rb +199 -192
  68. data/lib/active_record/connection_adapters/abstract/query_cache.rb +31 -26
  69. data/lib/active_record/connection_adapters/abstract/quoting.rb +140 -57
  70. data/lib/active_record/connection_adapters/abstract/savepoints.rb +21 -0
  71. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +147 -0
  72. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +419 -276
  73. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +105 -0
  74. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +963 -276
  75. data/lib/active_record/connection_adapters/abstract/transaction.rb +232 -0
  76. data/lib/active_record/connection_adapters/abstract_adapter.rb +397 -106
  77. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +643 -342
  78. data/lib/active_record/connection_adapters/column.rb +30 -259
  79. data/lib/active_record/connection_adapters/connection_specification.rb +263 -0
  80. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  81. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  82. data/lib/active_record/connection_adapters/mysql/database_statements.rb +125 -0
  83. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  84. data/lib/active_record/connection_adapters/mysql/quoting.rb +51 -0
  85. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +67 -0
  86. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +93 -0
  87. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +54 -0
  88. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  89. data/lib/active_record/connection_adapters/mysql2_adapter.rb +47 -196
  90. data/lib/active_record/connection_adapters/postgresql/column.rb +15 -0
  91. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +170 -0
  92. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  93. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +70 -0
  94. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
  95. data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
  96. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +15 -0
  97. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +48 -0
  98. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +21 -0
  99. data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
  100. data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +19 -0
  101. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
  102. data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
  103. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +10 -0
  104. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
  105. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +39 -0
  106. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
  107. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  108. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +93 -0
  109. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
  110. data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +109 -0
  111. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +21 -0
  112. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
  113. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
  114. data/lib/active_record/connection_adapters/postgresql/oid.rb +31 -0
  115. data/lib/active_record/connection_adapters/postgresql/quoting.rb +116 -0
  116. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +49 -0
  117. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +180 -0
  118. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +47 -0
  119. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +682 -0
  120. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  121. data/lib/active_record/connection_adapters/postgresql/utils.rb +77 -0
  122. data/lib/active_record/connection_adapters/postgresql_adapter.rb +558 -1039
  123. data/lib/active_record/connection_adapters/schema_cache.rb +74 -36
  124. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  125. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  126. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +48 -0
  127. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +22 -0
  128. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +538 -24
  129. data/lib/active_record/connection_adapters/statement_pool.rb +31 -12
  130. data/lib/active_record/connection_handling.rb +155 -0
  131. data/lib/active_record/core.rb +561 -0
  132. data/lib/active_record/counter_cache.rb +146 -105
  133. data/lib/active_record/dynamic_matchers.rb +101 -64
  134. data/lib/active_record/enum.rb +234 -0
  135. data/lib/active_record/errors.rb +153 -56
  136. data/lib/active_record/explain.rb +15 -63
  137. data/lib/active_record/explain_registry.rb +30 -0
  138. data/lib/active_record/explain_subscriber.rb +10 -6
  139. data/lib/active_record/fixture_set/file.rb +77 -0
  140. data/lib/active_record/fixtures.rb +355 -232
  141. data/lib/active_record/gem_version.rb +15 -0
  142. data/lib/active_record/inheritance.rb +144 -79
  143. data/lib/active_record/integration.rb +66 -13
  144. data/lib/active_record/internal_metadata.rb +56 -0
  145. data/lib/active_record/legacy_yaml_adapter.rb +46 -0
  146. data/lib/active_record/locale/en.yml +9 -1
  147. data/lib/active_record/locking/optimistic.rb +77 -56
  148. data/lib/active_record/locking/pessimistic.rb +6 -6
  149. data/lib/active_record/log_subscriber.rb +53 -28
  150. data/lib/active_record/migration/command_recorder.rb +166 -33
  151. data/lib/active_record/migration/compatibility.rb +126 -0
  152. data/lib/active_record/migration/join_table.rb +15 -0
  153. data/lib/active_record/migration.rb +792 -264
  154. data/lib/active_record/model_schema.rb +192 -130
  155. data/lib/active_record/nested_attributes.rb +238 -145
  156. data/lib/active_record/no_touching.rb +52 -0
  157. data/lib/active_record/null_relation.rb +89 -0
  158. data/lib/active_record/persistence.rb +357 -157
  159. data/lib/active_record/query_cache.rb +22 -43
  160. data/lib/active_record/querying.rb +34 -23
  161. data/lib/active_record/railtie.rb +88 -48
  162. data/lib/active_record/railties/console_sandbox.rb +3 -4
  163. data/lib/active_record/railties/controller_runtime.rb +5 -4
  164. data/lib/active_record/railties/databases.rake +170 -422
  165. data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
  166. data/lib/active_record/readonly_attributes.rb +2 -5
  167. data/lib/active_record/reflection.rb +715 -189
  168. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  169. data/lib/active_record/relation/batches.rb +203 -50
  170. data/lib/active_record/relation/calculations.rb +203 -194
  171. data/lib/active_record/relation/delegation.rb +103 -25
  172. data/lib/active_record/relation/finder_methods.rb +457 -261
  173. data/lib/active_record/relation/from_clause.rb +32 -0
  174. data/lib/active_record/relation/merger.rb +167 -0
  175. data/lib/active_record/relation/predicate_builder/array_handler.rb +43 -0
  176. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +88 -0
  177. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  178. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  179. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  180. data/lib/active_record/relation/predicate_builder/polymorphic_array_handler.rb +57 -0
  181. data/lib/active_record/relation/predicate_builder/range_handler.rb +33 -0
  182. data/lib/active_record/relation/predicate_builder/relation_handler.rb +13 -0
  183. data/lib/active_record/relation/predicate_builder.rb +153 -48
  184. data/lib/active_record/relation/query_attribute.rb +19 -0
  185. data/lib/active_record/relation/query_methods.rb +1019 -194
  186. data/lib/active_record/relation/record_fetch_warning.rb +49 -0
  187. data/lib/active_record/relation/spawn_methods.rb +46 -150
  188. data/lib/active_record/relation/where_clause.rb +174 -0
  189. data/lib/active_record/relation/where_clause_factory.rb +38 -0
  190. data/lib/active_record/relation.rb +450 -245
  191. data/lib/active_record/result.rb +104 -12
  192. data/lib/active_record/runtime_registry.rb +22 -0
  193. data/lib/active_record/sanitization.rb +120 -94
  194. data/lib/active_record/schema.rb +28 -18
  195. data/lib/active_record/schema_dumper.rb +141 -74
  196. data/lib/active_record/schema_migration.rb +50 -0
  197. data/lib/active_record/scoping/default.rb +64 -57
  198. data/lib/active_record/scoping/named.rb +93 -108
  199. data/lib/active_record/scoping.rb +73 -121
  200. data/lib/active_record/secure_token.rb +38 -0
  201. data/lib/active_record/serialization.rb +7 -5
  202. data/lib/active_record/statement_cache.rb +113 -0
  203. data/lib/active_record/store.rb +173 -15
  204. data/lib/active_record/suppressor.rb +58 -0
  205. data/lib/active_record/table_metadata.rb +68 -0
  206. data/lib/active_record/tasks/database_tasks.rb +313 -0
  207. data/lib/active_record/tasks/mysql_database_tasks.rb +151 -0
  208. data/lib/active_record/tasks/postgresql_database_tasks.rb +110 -0
  209. data/lib/active_record/tasks/sqlite_database_tasks.rb +59 -0
  210. data/lib/active_record/timestamp.rb +42 -24
  211. data/lib/active_record/touch_later.rb +58 -0
  212. data/lib/active_record/transactions.rb +233 -105
  213. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  214. data/lib/active_record/type/date.rb +7 -0
  215. data/lib/active_record/type/date_time.rb +7 -0
  216. data/lib/active_record/type/hash_lookup_type_map.rb +23 -0
  217. data/lib/active_record/type/internal/abstract_json.rb +29 -0
  218. data/lib/active_record/type/internal/timezone.rb +15 -0
  219. data/lib/active_record/type/serialized.rb +63 -0
  220. data/lib/active_record/type/time.rb +20 -0
  221. data/lib/active_record/type/type_map.rb +64 -0
  222. data/lib/active_record/type.rb +72 -0
  223. data/lib/active_record/type_caster/connection.rb +29 -0
  224. data/lib/active_record/type_caster/map.rb +19 -0
  225. data/lib/active_record/type_caster.rb +7 -0
  226. data/lib/active_record/validations/absence.rb +23 -0
  227. data/lib/active_record/validations/associated.rb +33 -18
  228. data/lib/active_record/validations/length.rb +24 -0
  229. data/lib/active_record/validations/presence.rb +66 -0
  230. data/lib/active_record/validations/uniqueness.rb +128 -68
  231. data/lib/active_record/validations.rb +48 -40
  232. data/lib/active_record/version.rb +5 -7
  233. data/lib/active_record.rb +71 -47
  234. data/lib/rails/generators/active_record/migration/migration_generator.rb +56 -8
  235. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +24 -0
  236. data/lib/rails/generators/active_record/migration/templates/migration.rb +28 -16
  237. data/lib/rails/generators/active_record/migration.rb +18 -8
  238. data/lib/rails/generators/active_record/model/model_generator.rb +38 -16
  239. data/lib/rails/generators/active_record/model/templates/application_record.rb +5 -0
  240. data/lib/rails/generators/active_record/model/templates/model.rb +7 -6
  241. data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
  242. data/lib/rails/generators/active_record.rb +3 -11
  243. metadata +188 -134
  244. data/examples/associations.png +0 -0
  245. data/lib/active_record/associations/has_and_belongs_to_many_association.rb +0 -63
  246. data/lib/active_record/associations/join_helper.rb +0 -55
  247. data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +0 -60
  248. data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
  249. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
  250. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -441
  251. data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
  252. data/lib/active_record/dynamic_finder_match.rb +0 -68
  253. data/lib/active_record/dynamic_scope_match.rb +0 -23
  254. data/lib/active_record/fixtures/file.rb +0 -65
  255. data/lib/active_record/identity_map.rb +0 -162
  256. data/lib/active_record/observer.rb +0 -121
  257. data/lib/active_record/serializers/xml_serializer.rb +0 -203
  258. data/lib/active_record/session_store.rb +0 -360
  259. data/lib/active_record/test_case.rb +0 -73
  260. data/lib/rails/generators/active_record/model/templates/migration.rb +0 -15
  261. data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
  262. data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
  263. data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
  264. data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
@@ -1,34 +1,179 @@
1
- require "active_support/core_ext/module/delegation"
2
- require "active_support/core_ext/class/attribute_accessors"
3
- require "active_support/core_ext/array/wrap"
4
- require 'active_support/deprecation'
1
+ require "active_support/core_ext/module/attribute_accessors"
2
+ require 'set'
5
3
 
6
4
  module ActiveRecord
7
- # Exception that can be raised to stop migrations from going backwards.
8
- class IrreversibleMigration < ActiveRecordError
5
+ class MigrationError < ActiveRecordError#:nodoc:
6
+ def initialize(message = nil)
7
+ message = "\n\n#{message}\n\n" if message
8
+ super
9
+ end
9
10
  end
10
11
 
11
- class DuplicateMigrationVersionError < ActiveRecordError#:nodoc:
12
- def initialize(version)
13
- super("Multiple migrations have the version number #{version}")
12
+ # Exception that can be raised to stop migrations from being rolled back.
13
+ # For example the following migration is not reversible.
14
+ # Rolling back this migration will raise an ActiveRecord::IrreversibleMigration error.
15
+ #
16
+ # class IrreversibleMigrationExample < ActiveRecord::Migration[5.0]
17
+ # def change
18
+ # create_table :distributors do |t|
19
+ # t.string :zipcode
20
+ # end
21
+ #
22
+ # execute <<-SQL
23
+ # ALTER TABLE distributors
24
+ # ADD CONSTRAINT zipchk
25
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
26
+ # SQL
27
+ # end
28
+ # end
29
+ #
30
+ # There are two ways to mitigate this problem.
31
+ #
32
+ # 1. Define <tt>#up</tt> and <tt>#down</tt> methods instead of <tt>#change</tt>:
33
+ #
34
+ # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
35
+ # def up
36
+ # create_table :distributors do |t|
37
+ # t.string :zipcode
38
+ # end
39
+ #
40
+ # execute <<-SQL
41
+ # ALTER TABLE distributors
42
+ # ADD CONSTRAINT zipchk
43
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
44
+ # SQL
45
+ # end
46
+ #
47
+ # def down
48
+ # execute <<-SQL
49
+ # ALTER TABLE distributors
50
+ # DROP CONSTRAINT zipchk
51
+ # SQL
52
+ #
53
+ # drop_table :distributors
54
+ # end
55
+ # end
56
+ #
57
+ # 2. Use the #reversible method in <tt>#change</tt> method:
58
+ #
59
+ # class ReversibleMigrationExample < ActiveRecord::Migration[5.0]
60
+ # def change
61
+ # create_table :distributors do |t|
62
+ # t.string :zipcode
63
+ # end
64
+ #
65
+ # reversible do |dir|
66
+ # dir.up do
67
+ # execute <<-SQL
68
+ # ALTER TABLE distributors
69
+ # ADD CONSTRAINT zipchk
70
+ # CHECK (char_length(zipcode) = 5) NO INHERIT;
71
+ # SQL
72
+ # end
73
+ #
74
+ # dir.down do
75
+ # execute <<-SQL
76
+ # ALTER TABLE distributors
77
+ # DROP CONSTRAINT zipchk
78
+ # SQL
79
+ # end
80
+ # end
81
+ # end
82
+ # end
83
+ class IrreversibleMigration < MigrationError
84
+ end
85
+
86
+ class DuplicateMigrationVersionError < MigrationError#:nodoc:
87
+ def initialize(version = nil)
88
+ if version
89
+ super("Multiple migrations have the version number #{version}.")
90
+ else
91
+ super("Duplicate migration version error.")
92
+ end
93
+ end
94
+ end
95
+
96
+ class DuplicateMigrationNameError < MigrationError#:nodoc:
97
+ def initialize(name = nil)
98
+ if name
99
+ super("Multiple migrations have the name #{name}.")
100
+ else
101
+ super("Duplicate migration name.")
102
+ end
14
103
  end
15
104
  end
16
105
 
17
- class DuplicateMigrationNameError < ActiveRecordError#:nodoc:
18
- def initialize(name)
19
- super("Multiple migrations have the name #{name}")
106
+ class UnknownMigrationVersionError < MigrationError #:nodoc:
107
+ def initialize(version = nil)
108
+ if version
109
+ super("No migration with version number #{version}.")
110
+ else
111
+ super("Unknown migration version.")
112
+ end
20
113
  end
21
114
  end
22
115
 
23
- class UnknownMigrationVersionError < ActiveRecordError #:nodoc:
24
- def initialize(version)
25
- super("No migration with version number #{version}")
116
+ class IllegalMigrationNameError < MigrationError#:nodoc:
117
+ def initialize(name = nil)
118
+ if name
119
+ super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed).")
120
+ else
121
+ super("Illegal name for migration.")
122
+ end
26
123
  end
27
124
  end
28
125
 
29
- class IllegalMigrationNameError < ActiveRecordError#:nodoc:
30
- def initialize(name)
31
- super("Illegal name for migration file: #{name}\n\t(only lower case letters, numbers, and '_' allowed)")
126
+ class PendingMigrationError < MigrationError#:nodoc:
127
+ def initialize(message = nil)
128
+ if !message && defined?(Rails.env)
129
+ super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate RAILS_ENV=#{::Rails.env}")
130
+ elsif !message
131
+ super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate")
132
+ else
133
+ super
134
+ end
135
+ end
136
+ end
137
+
138
+ class ConcurrentMigrationError < MigrationError #:nodoc:
139
+ DEFAULT_MESSAGE = "Cannot run migrations because another migration process is currently running.".freeze
140
+
141
+ def initialize(message = DEFAULT_MESSAGE)
142
+ super
143
+ end
144
+ end
145
+
146
+ class NoEnvironmentInSchemaError < MigrationError #:nodoc:
147
+ def initialize
148
+ msg = "Environment data not found in the schema. To resolve this issue, run: \n\n\tbin/rails db:environment:set"
149
+ if defined?(Rails.env)
150
+ super("#{msg} RAILS_ENV=#{::Rails.env}")
151
+ else
152
+ super(msg)
153
+ end
154
+ end
155
+ end
156
+
157
+ class ProtectedEnvironmentError < ActiveRecordError #:nodoc:
158
+ def initialize(env = "production")
159
+ msg = "You are attempting to run a destructive action against your '#{env}' database.\n"
160
+ msg << "If you are sure you want to continue, run the same command with the environment variable:\n"
161
+ msg << "DISABLE_DATABASE_ENVIRONMENT_CHECK=1"
162
+ super(msg)
163
+ end
164
+ end
165
+
166
+ class EnvironmentMismatchError < ActiveRecordError
167
+ def initialize(current: nil, stored: nil)
168
+ msg = "You are attempting to modify a database that was last run in `#{ stored }` environment.\n"
169
+ msg << "You are running in `#{ current }` environment. "
170
+ msg << "If you are sure you want to continue, first set the environment using:\n\n"
171
+ msg << "\tbin/rails db:environment:set"
172
+ if defined?(Rails.env)
173
+ super("#{msg} RAILS_ENV=#{::Rails.env}\n\n")
174
+ else
175
+ super("#{msg}\n\n")
176
+ end
32
177
  end
33
178
  end
34
179
 
@@ -44,9 +189,9 @@ module ActiveRecord
44
189
  #
45
190
  # Example of a simple migration:
46
191
  #
47
- # class AddSsl < ActiveRecord::Migration
192
+ # class AddSsl < ActiveRecord::Migration[5.0]
48
193
  # def up
49
- # add_column :accounts, :ssl_enabled, :boolean, :default => 1
194
+ # add_column :accounts, :ssl_enabled, :boolean, default: true
50
195
  # end
51
196
  #
52
197
  # def down
@@ -58,13 +203,13 @@ module ActiveRecord
58
203
  # if you're backing out of the migration. It shows how all migrations have
59
204
  # two methods +up+ and +down+ that describes the transformations
60
205
  # required to implement or remove the migration. These methods can consist
61
- # of both the migration specific methods like add_column and remove_column,
206
+ # of both the migration specific methods like +add_column+ and +remove_column+,
62
207
  # but may also contain regular Ruby code for generating data needed for the
63
208
  # transformations.
64
209
  #
65
210
  # Example of a more complex migration that also needs to initialize data:
66
211
  #
67
- # class AddSystemSettings < ActiveRecord::Migration
212
+ # class AddSystemSettings < ActiveRecord::Migration[5.0]
68
213
  # def up
69
214
  # create_table :system_settings do |t|
70
215
  # t.string :name
@@ -74,9 +219,9 @@ module ActiveRecord
74
219
  # t.integer :position
75
220
  # end
76
221
  #
77
- # SystemSetting.create :name => "notice",
78
- # :label => "Use notice?",
79
- # :value => 1
222
+ # SystemSetting.create name: 'notice',
223
+ # label: 'Use notice?',
224
+ # value: 1
80
225
  # end
81
226
  #
82
227
  # def down
@@ -84,46 +229,88 @@ module ActiveRecord
84
229
  # end
85
230
  # end
86
231
  #
87
- # This migration first adds the system_settings table, then creates the very
232
+ # This migration first adds the +system_settings+ table, then creates the very
88
233
  # first row in it using the Active Record model that relies on the table. It
89
- # also uses the more advanced create_table syntax where you can specify a
234
+ # also uses the more advanced +create_table+ syntax where you can specify a
90
235
  # complete table schema in one block call.
91
236
  #
92
237
  # == Available transformations
93
238
  #
94
- # * <tt>create_table(name, options)</tt> Creates a table called +name+ and
239
+ # === Creation
240
+ #
241
+ # * <tt>create_join_table(table_1, table_2, options)</tt>: Creates a join
242
+ # table having its name as the lexical order of the first two
243
+ # arguments. See
244
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#create_join_table for
245
+ # details.
246
+ # * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
95
247
  # makes the table object available to a block that can then add columns to it,
96
- # following the same format as add_column. See example above. The options hash
248
+ # following the same format as +add_column+. See example above. The options hash
97
249
  # is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
98
250
  # table definition.
99
- # * <tt>drop_table(name)</tt>: Drops the table called +name+.
100
- # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
101
- # to +new_name+.
102
251
  # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
103
252
  # to the table called +table_name+
104
253
  # named +column_name+ specified to be one of the following types:
105
254
  # <tt>:string</tt>, <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>,
106
255
  # <tt>:decimal</tt>, <tt>:datetime</tt>, <tt>:timestamp</tt>, <tt>:time</tt>,
107
256
  # <tt>:date</tt>, <tt>:binary</tt>, <tt>:boolean</tt>. A default value can be
108
- # specified by passing an +options+ hash like <tt>{ :default => 11 }</tt>.
257
+ # specified by passing an +options+ hash like <tt>{ default: 11 }</tt>.
109
258
  # Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
110
- # <tt>{ :limit => 50, :null => false }</tt>) -- see
259
+ # <tt>{ limit: 50, null: false }</tt>) -- see
111
260
  # ActiveRecord::ConnectionAdapters::TableDefinition#column for details.
112
- # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
113
- # a column but keeps the type and content.
114
- # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
115
- # the column to a different type using the same parameters as add_column.
116
- # * <tt>remove_column(table_name, column_names)</tt>: Removes the column listed in
117
- # +column_names+ from the table called +table_name+.
261
+ # * <tt>add_foreign_key(from_table, to_table, options)</tt>: Adds a new
262
+ # foreign key. +from_table+ is the table with the key column, +to_table+ contains
263
+ # the referenced primary key.
118
264
  # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
119
265
  # with the name of the column. Other options include
120
266
  # <tt>:name</tt>, <tt>:unique</tt> (e.g.
121
- # <tt>{ :name => "users_name_index", :unique => true }</tt>) and <tt>:order</tt>
122
- # (e.g. { :order => {:name => :desc} }</tt>).
123
- # * <tt>remove_index(table_name, :column => column_name)</tt>: Removes the index
124
- # specified by +column_name+.
125
- # * <tt>remove_index(table_name, :name => index_name)</tt>: Removes the index
267
+ # <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
268
+ # (e.g. <tt>{ order: { name: :desc } }</tt>).
269
+ # * <tt>add_reference(:table_name, :reference_name)</tt>: Adds a new column
270
+ # +reference_name_id+ by default an integer. See
271
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference for details.
272
+ # * <tt>add_timestamps(table_name, options)</tt>: Adds timestamps (+created_at+
273
+ # and +updated_at+) columns to +table_name+.
274
+ #
275
+ # === Modification
276
+ #
277
+ # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
278
+ # the column to a different type using the same parameters as add_column.
279
+ # * <tt>change_column_default(table_name, column_name, default)</tt>: Sets a
280
+ # default value for +column_name+ defined by +default+ on +table_name+.
281
+ # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
282
+ # Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
283
+ # indicates whether the value can be +NULL+. See
284
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
285
+ # details.
286
+ # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
287
+ # the table called +name+. It makes the table object available to a block that
288
+ # can then add/remove columns, indexes or foreign keys to it.
289
+ # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
290
+ # a column but keeps the type and content.
291
+ # * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
292
+ # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
293
+ # to +new_name+.
294
+ #
295
+ # === Deletion
296
+ #
297
+ # * <tt>drop_table(name)</tt>: Drops the table called +name+.
298
+ # * <tt>drop_join_table(table_1, table_2, options)</tt>: Drops the join table
299
+ # specified by the given arguments.
300
+ # * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
301
+ # named +column_name+ from the table called +table_name+.
302
+ # * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
303
+ # columns from the table definition.
304
+ # * <tt>remove_foreign_key(from_table, options_or_to_table)</tt>: Removes the
305
+ # given foreign key from the table called +table_name+.
306
+ # * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
307
+ # specified by +column_names+.
308
+ # * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
126
309
  # specified by +index_name+.
310
+ # * <tt>remove_reference(table_name, ref_name, options)</tt>: Removes the
311
+ # reference(s) on +table_name+ specified by +ref_name+.
312
+ # * <tt>remove_timestamps(table_name, options)</tt>: Removes the timestamp
313
+ # columns (+created_at+ and +updated_at+) from the table definition.
127
314
  #
128
315
  # == Irreversible transformations
129
316
  #
@@ -143,47 +330,43 @@ module ActiveRecord
143
330
  # in the <tt>db/migrate/</tt> directory where <tt>timestamp</tt> is the
144
331
  # UTC formatted date and time that the migration was generated.
145
332
  #
146
- # You may then edit the <tt>up</tt> and <tt>down</tt> methods of
147
- # MyNewMigration.
148
- #
149
333
  # There is a special syntactic shortcut to generate migrations that add fields to a table.
150
334
  #
151
335
  # rails generate migration add_fieldname_to_tablename fieldname:string
152
336
  #
153
- # This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
154
- # class AddFieldnameToTablename < ActiveRecord::Migration
155
- # def up
337
+ # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
338
+ # class AddFieldnameToTablename < ActiveRecord::Migration[5.0]
339
+ # def change
156
340
  # add_column :tablenames, :fieldname, :string
157
341
  # end
158
- #
159
- # def down
160
- # remove_column :tablenames, :fieldname
161
- # end
162
342
  # end
163
343
  #
164
344
  # To run migrations against the currently configured database, use
165
- # <tt>rake db:migrate</tt>. This will update the database by running all of the
345
+ # <tt>rails db:migrate</tt>. This will update the database by running all of the
166
346
  # pending migrations, creating the <tt>schema_migrations</tt> table
167
347
  # (see "About the schema_migrations table" section below) if missing. It will also
168
348
  # invoke the db:schema:dump task, which will update your db/schema.rb file
169
349
  # to match the structure of your database.
170
350
  #
171
351
  # To roll the database back to a previous migration version, use
172
- # <tt>rake db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
173
- # you wish to downgrade. If any of the migrations throw an
174
- # <tt>ActiveRecord::IrreversibleMigration</tt> exception, that step will fail and you'll
175
- # have some manual work to do.
352
+ # <tt>rails db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
353
+ # you wish to downgrade. Alternatively, you can also use the STEP option if you
354
+ # wish to rollback last few migrations. <tt>rails db:migrate STEP=2</tt> will rollback
355
+ # the latest two migrations.
356
+ #
357
+ # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
358
+ # that step will fail and you'll have some manual work to do.
176
359
  #
177
360
  # == Database support
178
361
  #
179
362
  # Migrations are currently supported in MySQL, PostgreSQL, SQLite,
180
- # SQL Server, Sybase, and Oracle (all supported databases except DB2).
363
+ # SQL Server, and Oracle (all supported databases except DB2).
181
364
  #
182
365
  # == More examples
183
366
  #
184
367
  # Not all migrations change the schema. Some just fix the data:
185
368
  #
186
- # class RemoveEmptyTags < ActiveRecord::Migration
369
+ # class RemoveEmptyTags < ActiveRecord::Migration[5.0]
187
370
  # def up
188
371
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
189
372
  # end
@@ -196,7 +379,7 @@ module ActiveRecord
196
379
  #
197
380
  # Others remove columns when they migrate up instead of down:
198
381
  #
199
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
382
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[5.0]
200
383
  # def up
201
384
  # remove_column :items, :incomplete_items_count
202
385
  # remove_column :items, :completed_items_count
@@ -210,7 +393,7 @@ module ActiveRecord
210
393
  #
211
394
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
212
395
  #
213
- # class MakeJoinUnique < ActiveRecord::Migration
396
+ # class MakeJoinUnique < ActiveRecord::Migration[5.0]
214
397
  # def up
215
398
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
216
399
  # end
@@ -227,7 +410,7 @@ module ActiveRecord
227
410
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
228
411
  # latest column data from after the new column was added. Example:
229
412
  #
230
- # class AddPeopleSalary < ActiveRecord::Migration
413
+ # class AddPeopleSalary < ActiveRecord::Migration[5.0]
231
414
  # def up
232
415
  # add_column :people, :salary, :integer
233
416
  # Person.reset_column_information
@@ -261,21 +444,6 @@ module ActiveRecord
261
444
  # The phrase "Updating salaries..." would then be printed, along with the
262
445
  # benchmark for the block when the block completes.
263
446
  #
264
- # == About the schema_migrations table
265
- #
266
- # Rails versions 2.0 and prior used to create a table called
267
- # <tt>schema_info</tt> when using migrations. This table contained the
268
- # version of the schema as of the last applied migration.
269
- #
270
- # Starting with Rails 2.1, the <tt>schema_info</tt> table is
271
- # (automatically) replaced by the <tt>schema_migrations</tt> table, which
272
- # contains the version numbers of all the migrations applied.
273
- #
274
- # As a result, it is now possible to add migration files that are numbered
275
- # lower than the current schema version: when migrating up, those
276
- # never-applied "interleaved" migrations will be automatically applied, and
277
- # when migrating down, never-applied "interleaved" migrations will be skipped.
278
- #
279
447
  # == Timestamped Migrations
280
448
  #
281
449
  # By default, Rails generates migrations that look like:
@@ -293,15 +461,14 @@ module ActiveRecord
293
461
  #
294
462
  # == Reversible Migrations
295
463
  #
296
- # Starting with Rails 3.1, you will be able to define reversible migrations.
297
464
  # Reversible migrations are migrations that know how to go +down+ for you.
298
- # You simply supply the +up+ logic, and the Migration system will figure out
465
+ # You simply supply the +up+ logic, and the Migration system figures out
299
466
  # how to execute the down commands for you.
300
467
  #
301
468
  # To define a reversible migration, define the +change+ method in your
302
469
  # migration like this:
303
470
  #
304
- # class TenderloveMigration < ActiveRecord::Migration
471
+ # class TenderloveMigration < ActiveRecord::Migration[5.0]
305
472
  # def change
306
473
  # create_table(:horses) do |t|
307
474
  # t.column :content, :text
@@ -323,45 +490,259 @@ module ActiveRecord
323
490
  #
324
491
  # For a list of commands that are reversible, please see
325
492
  # <tt>ActiveRecord::Migration::CommandRecorder</tt>.
493
+ #
494
+ # == Transactional Migrations
495
+ #
496
+ # If the database adapter supports DDL transactions, all migrations will
497
+ # automatically be wrapped in a transaction. There are queries that you
498
+ # can't execute inside a transaction though, and for these situations
499
+ # you can turn the automatic transactions off.
500
+ #
501
+ # class ChangeEnum < ActiveRecord::Migration[5.0]
502
+ # disable_ddl_transaction!
503
+ #
504
+ # def up
505
+ # execute "ALTER TYPE model_size ADD VALUE 'new_value'"
506
+ # end
507
+ # end
508
+ #
509
+ # Remember that you can still open your own transactions, even if you
510
+ # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
326
511
  class Migration
327
512
  autoload :CommandRecorder, 'active_record/migration/command_recorder'
513
+ autoload :Compatibility, 'active_record/migration/compatibility'
514
+
515
+ # This must be defined before the inherited hook, below
516
+ class Current < Migration # :nodoc:
517
+ end
518
+
519
+ def self.inherited(subclass) # :nodoc:
520
+ super
521
+ if subclass.superclass == Migration
522
+ subclass.include Compatibility::Legacy
523
+ end
524
+ end
525
+
526
+ def self.[](version)
527
+ Compatibility.find(version)
528
+ end
529
+
530
+ def self.current_version
531
+ ActiveRecord::VERSION::STRING.to_f
532
+ end
533
+
534
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
535
+
536
+ # This class is used to verify that all migrations have been run before
537
+ # loading a web page if <tt>config.active_record.migration_error</tt> is set to :page_load
538
+ class CheckPending
539
+ def initialize(app)
540
+ @app = app
541
+ @last_check = 0
542
+ end
543
+
544
+ def call(env)
545
+ if connection.supports_migrations?
546
+ mtime = ActiveRecord::Migrator.last_migration.mtime.to_i
547
+ if @last_check < mtime
548
+ ActiveRecord::Migration.check_pending!(connection)
549
+ @last_check = mtime
550
+ end
551
+ end
552
+ @app.call(env)
553
+ end
554
+
555
+ private
556
+
557
+ def connection
558
+ ActiveRecord::Base.connection
559
+ end
560
+ end
328
561
 
329
562
  class << self
330
563
  attr_accessor :delegate # :nodoc:
331
- end
564
+ attr_accessor :disable_ddl_transaction # :nodoc:
565
+
566
+ def nearest_delegate # :nodoc:
567
+ delegate || superclass.nearest_delegate
568
+ end
569
+
570
+ # Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
571
+ def check_pending!(connection = Base.connection)
572
+ raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
573
+ end
574
+
575
+ def load_schema_if_pending!
576
+ if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
577
+ # Roundtrip to Rake to allow plugins to hook into database initialization.
578
+ FileUtils.cd Rails.root do
579
+ current_config = Base.connection_config
580
+ Base.clear_all_connections!
581
+ system("bin/rails db:test:prepare")
582
+ # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
583
+ Base.establish_connection(current_config)
584
+ end
585
+ check_pending!
586
+ end
587
+ end
588
+
589
+ def maintain_test_schema! # :nodoc:
590
+ if ActiveRecord::Base.maintain_test_schema
591
+ suppress_messages { load_schema_if_pending! }
592
+ end
593
+ end
332
594
 
333
- def self.method_missing(name, *args, &block) # :nodoc:
334
- (delegate || superclass.delegate).send(name, *args, &block)
595
+ def method_missing(name, *args, &block) # :nodoc:
596
+ nearest_delegate.send(name, *args, &block)
597
+ end
598
+
599
+ def migrate(direction)
600
+ new.migrate direction
601
+ end
602
+
603
+ # Disable the transaction wrapping this migration.
604
+ # You can still create your own transactions even after calling #disable_ddl_transaction!
605
+ #
606
+ # For more details read the {"Transactional Migrations" section above}[rdoc-ref:Migration].
607
+ def disable_ddl_transaction!
608
+ @disable_ddl_transaction = true
609
+ end
335
610
  end
336
611
 
337
- def self.migrate(direction)
338
- new.migrate direction
612
+ def disable_ddl_transaction # :nodoc:
613
+ self.class.disable_ddl_transaction
339
614
  end
340
615
 
341
616
  cattr_accessor :verbose
342
-
343
617
  attr_accessor :name, :version
344
618
 
345
- def initialize
346
- @name = self.class.name
347
- @version = nil
619
+ def initialize(name = self.class.name, version = nil)
620
+ @name = name
621
+ @version = version
348
622
  @connection = nil
349
- @reverting = false
350
623
  end
351
624
 
625
+ self.verbose = true
352
626
  # instantiate the delegate object after initialize is defined
353
- self.verbose = true
354
627
  self.delegate = new
355
628
 
356
- def revert
357
- @reverting = true
358
- yield
359
- ensure
360
- @reverting = false
629
+ # Reverses the migration commands for the given block and
630
+ # the given migrations.
631
+ #
632
+ # The following migration will remove the table 'horses'
633
+ # and create the table 'apples' on the way up, and the reverse
634
+ # on the way down.
635
+ #
636
+ # class FixTLMigration < ActiveRecord::Migration[5.0]
637
+ # def change
638
+ # revert do
639
+ # create_table(:horses) do |t|
640
+ # t.text :content
641
+ # t.datetime :remind_at
642
+ # end
643
+ # end
644
+ # create_table(:apples) do |t|
645
+ # t.string :variety
646
+ # end
647
+ # end
648
+ # end
649
+ #
650
+ # Or equivalently, if +TenderloveMigration+ is defined as in the
651
+ # documentation for Migration:
652
+ #
653
+ # require_relative '20121212123456_tenderlove_migration'
654
+ #
655
+ # class FixupTLMigration < ActiveRecord::Migration[5.0]
656
+ # def change
657
+ # revert TenderloveMigration
658
+ #
659
+ # create_table(:apples) do |t|
660
+ # t.string :variety
661
+ # end
662
+ # end
663
+ # end
664
+ #
665
+ # This command can be nested.
666
+ def revert(*migration_classes)
667
+ run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
668
+ if block_given?
669
+ if connection.respond_to? :revert
670
+ connection.revert { yield }
671
+ else
672
+ recorder = CommandRecorder.new(connection)
673
+ @connection = recorder
674
+ suppress_messages do
675
+ connection.revert { yield }
676
+ end
677
+ @connection = recorder.delegate
678
+ recorder.commands.each do |cmd, args, block|
679
+ send(cmd, *args, &block)
680
+ end
681
+ end
682
+ end
361
683
  end
362
684
 
363
685
  def reverting?
364
- @reverting
686
+ connection.respond_to?(:reverting) && connection.reverting
687
+ end
688
+
689
+ class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
690
+ def up
691
+ yield unless reverting
692
+ end
693
+
694
+ def down
695
+ yield if reverting
696
+ end
697
+ end
698
+
699
+ # Used to specify an operation that can be run in one direction or another.
700
+ # Call the methods +up+ and +down+ of the yielded object to run a block
701
+ # only in one given direction.
702
+ # The whole block will be called in the right order within the migration.
703
+ #
704
+ # In the following example, the looping on users will always be done
705
+ # when the three columns 'first_name', 'last_name' and 'full_name' exist,
706
+ # even when migrating down:
707
+ #
708
+ # class SplitNameMigration < ActiveRecord::Migration[5.0]
709
+ # def change
710
+ # add_column :users, :first_name, :string
711
+ # add_column :users, :last_name, :string
712
+ #
713
+ # reversible do |dir|
714
+ # User.reset_column_information
715
+ # User.all.each do |u|
716
+ # dir.up { u.first_name, u.last_name = u.full_name.split(' ') }
717
+ # dir.down { u.full_name = "#{u.first_name} #{u.last_name}" }
718
+ # u.save
719
+ # end
720
+ # end
721
+ #
722
+ # revert { add_column :users, :full_name, :string }
723
+ # end
724
+ # end
725
+ def reversible
726
+ helper = ReversibleBlockHelper.new(reverting?)
727
+ execute_block{ yield helper }
728
+ end
729
+
730
+ # Runs the given migration classes.
731
+ # Last argument can specify options:
732
+ # - :direction (default is :up)
733
+ # - :revert (default is false)
734
+ def run(*migration_classes)
735
+ opts = migration_classes.extract_options!
736
+ dir = opts[:direction] || :up
737
+ dir = (dir == :down ? :up : :down) if opts[:revert]
738
+ if reverting?
739
+ # If in revert and going :up, say, we want to execute :down without reverting, so
740
+ revert { run(*migration_classes, direction: dir, revert: true) }
741
+ else
742
+ migration_classes.each do |migration_class|
743
+ migration_class.new.exec_migration(connection, dir)
744
+ end
745
+ end
365
746
  end
366
747
 
367
748
  def up
@@ -387,29 +768,9 @@ module ActiveRecord
387
768
 
388
769
  time = nil
389
770
  ActiveRecord::Base.connection_pool.with_connection do |conn|
390
- @connection = conn
391
- if respond_to?(:change)
392
- if direction == :down
393
- recorder = CommandRecorder.new(@connection)
394
- suppress_messages do
395
- @connection = recorder
396
- change
397
- end
398
- @connection = conn
399
- time = Benchmark.measure {
400
- self.revert {
401
- recorder.inverse.each do |cmd, args|
402
- send(cmd, *args)
403
- end
404
- }
405
- }
406
- else
407
- time = Benchmark.measure { change }
408
- end
409
- else
410
- time = Benchmark.measure { send(direction) }
771
+ time = Benchmark.measure do
772
+ exec_migration(conn, direction)
411
773
  end
412
- @connection = nil
413
774
  end
414
775
 
415
776
  case direction
@@ -418,6 +779,21 @@ module ActiveRecord
418
779
  end
419
780
  end
420
781
 
782
+ def exec_migration(conn, direction)
783
+ @connection = conn
784
+ if respond_to?(:change)
785
+ if direction == :down
786
+ revert { change }
787
+ else
788
+ change
789
+ end
790
+ else
791
+ send(direction)
792
+ end
793
+ ensure
794
+ @connection = nil
795
+ end
796
+
421
797
  def write(text="")
422
798
  puts(text) if verbose
423
799
  end
@@ -453,13 +829,16 @@ module ActiveRecord
453
829
  end
454
830
 
455
831
  def method_missing(method, *arguments, &block)
456
- arg_list = arguments.map{ |a| a.inspect } * ', '
832
+ arg_list = arguments.map(&:inspect) * ', '
457
833
 
458
834
  say_with_time "#{method}(#{arg_list})" do
459
- unless reverting?
460
- unless arguments.empty? || method == :execute
461
- arguments[0] = Migrator.proper_table_name(arguments.first) unless method == :assume_migrated_upto_version
462
- arguments[1] = Migrator.proper_table_name(arguments.second) if method == :rename_table
835
+ unless connection.respond_to? :revert
836
+ unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
837
+ arguments[0] = proper_table_name(arguments.first, table_name_options)
838
+ if [:rename_table, :add_foreign_key].include?(method) ||
839
+ (method == :remove_foreign_key && !arguments.second.is_a?(Hash))
840
+ arguments[1] = proper_table_name(arguments.second, table_name_options)
841
+ end
463
842
  end
464
843
  end
465
844
  return super unless connection.respond_to?(method)
@@ -470,7 +849,7 @@ module ActiveRecord
470
849
  def copy(destination, sources, options = {})
471
850
  copied = []
472
851
 
473
- FileUtils.mkdir_p(destination) unless File.exists?(destination)
852
+ FileUtils.mkdir_p(destination) unless File.exist?(destination)
474
853
 
475
854
  destination_migrations = ActiveRecord::Migrator.migrations(destination)
476
855
  last = destination_migrations.last
@@ -478,8 +857,17 @@ module ActiveRecord
478
857
  source_migrations = ActiveRecord::Migrator.migrations(path)
479
858
 
480
859
  source_migrations.each do |migration|
481
- source = File.read(migration.filename)
482
- source = "# This migration comes from #{scope} (originally #{migration.version})\n#{source}"
860
+ source = File.binread(migration.filename)
861
+ inserted_comment = "# This migration comes from #{scope} (originally #{migration.version})\n"
862
+ if /\A#.*\b(?:en)?coding:\s*\S+/ =~ source
863
+ # If we have a magic comment in the original migration,
864
+ # insert our comment after the first newline(end of the magic comment line)
865
+ # so the magic keep working.
866
+ # Note that magic comments must be at the first line(except sh-bang).
867
+ source[/\n/] = "\n#{inserted_comment}"
868
+ else
869
+ source = "#{inserted_comment}#{source}"
870
+ end
483
871
 
484
872
  if duplicate = destination_migrations.detect { |m| m.name == migration.name }
485
873
  if options[:on_skip] && duplicate.scope != scope.to_s
@@ -493,7 +881,7 @@ module ActiveRecord
493
881
  old_path, migration.filename = migration.filename, new_path
494
882
  last = migration
495
883
 
496
- File.open(migration.filename, "w") { |f| f.write source }
884
+ File.binwrite(migration.filename, source)
497
885
  copied << migration
498
886
  options[:on_copy].call(scope, migration, old_path) if options[:on_copy]
499
887
  destination_migrations << migration
@@ -503,11 +891,41 @@ module ActiveRecord
503
891
  copied
504
892
  end
505
893
 
894
+ # Finds the correct table name given an Active Record object.
895
+ # Uses the Active Record object's own table_name, or pre/suffix from the
896
+ # options passed in.
897
+ def proper_table_name(name, options = {})
898
+ if name.respond_to? :table_name
899
+ name.table_name
900
+ else
901
+ "#{options[:table_name_prefix]}#{name}#{options[:table_name_suffix]}"
902
+ end
903
+ end
904
+
905
+ # Determines the version number of the next migration.
506
906
  def next_migration_number(number)
507
907
  if ActiveRecord::Base.timestamped_migrations
508
908
  [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % number].max
509
909
  else
510
- "%.3d" % number
910
+ SchemaMigration.normalize_migration_number(number)
911
+ end
912
+ end
913
+
914
+ # Builds a hash for use in ActiveRecord::Migration#proper_table_name using
915
+ # the Active Record object's table_name prefix and suffix
916
+ def table_name_options(config = ActiveRecord::Base) #:nodoc:
917
+ {
918
+ table_name_prefix: config.table_name_prefix,
919
+ table_name_suffix: config.table_name_suffix
920
+ }
921
+ end
922
+
923
+ private
924
+ def execute_block
925
+ if connection.respond_to? :execute_block
926
+ super # use normal delegation to record the block
927
+ else
928
+ yield
511
929
  end
512
930
  end
513
931
  end
@@ -525,7 +943,11 @@ module ActiveRecord
525
943
  File.basename(filename)
526
944
  end
527
945
 
528
- delegate :migrate, :announce, :write, :to => :migration
946
+ def mtime
947
+ File.mtime filename
948
+ end
949
+
950
+ delegate :migrate, :announce, :write, :disable_ddl_transaction, to: :migration
529
951
 
530
952
  private
531
953
 
@@ -535,11 +957,21 @@ module ActiveRecord
535
957
 
536
958
  def load_migration
537
959
  require(File.expand_path(filename))
538
- name.constantize.new
960
+ name.constantize.new(name, version)
539
961
  end
540
962
 
541
963
  end
542
964
 
965
+ class NullMigration < MigrationProxy #:nodoc:
966
+ def initialize
967
+ super(nil, 0, nil, nil)
968
+ end
969
+
970
+ def mtime
971
+ 0
972
+ end
973
+ end
974
+
543
975
  class Migrator#:nodoc:
544
976
  class << self
545
977
  attr_writer :migrations_paths
@@ -547,14 +979,14 @@ module ActiveRecord
547
979
 
548
980
  def migrate(migrations_paths, target_version = nil, &block)
549
981
  case
550
- when target_version.nil?
551
- up(migrations_paths, target_version, &block)
552
- when current_version == 0 && target_version == 0
553
- []
554
- when current_version > target_version
555
- down(migrations_paths, target_version, &block)
556
- else
557
- up(migrations_paths, target_version, &block)
982
+ when target_version.nil?
983
+ up(migrations_paths, target_version, &block)
984
+ when current_version == 0 && target_version == 0
985
+ []
986
+ when current_version > target_version
987
+ down(migrations_paths, target_version, &block)
988
+ else
989
+ up(migrations_paths, target_version, &block)
558
990
  end
559
991
  end
560
992
 
@@ -566,78 +998,83 @@ module ActiveRecord
566
998
  move(:up, migrations_paths, steps)
567
999
  end
568
1000
 
569
- def up(migrations_paths, target_version = nil, &block)
570
- self.new(:up, migrations_paths, target_version).migrate(&block)
1001
+ def up(migrations_paths, target_version = nil)
1002
+ migrations = migrations(migrations_paths)
1003
+ migrations.select! { |m| yield m } if block_given?
1004
+
1005
+ new(:up, migrations, target_version).migrate
571
1006
  end
572
1007
 
573
- def down(migrations_paths, target_version = nil, &block)
574
- self.new(:down, migrations_paths, target_version).migrate(&block)
1008
+ def down(migrations_paths, target_version = nil)
1009
+ migrations = migrations(migrations_paths)
1010
+ migrations.select! { |m| yield m } if block_given?
1011
+
1012
+ new(:down, migrations, target_version).migrate
575
1013
  end
576
1014
 
577
1015
  def run(direction, migrations_paths, target_version)
578
- self.new(direction, migrations_paths, target_version).run
1016
+ new(direction, migrations(migrations_paths), target_version).run
579
1017
  end
580
1018
 
581
- def schema_migrations_table_name
582
- Base.table_name_prefix + 'schema_migrations' + Base.table_name_suffix
1019
+ def open(migrations_paths)
1020
+ new(:up, migrations(migrations_paths), nil)
583
1021
  end
584
1022
 
585
- def get_all_versions
586
- table = Arel::Table.new(schema_migrations_table_name)
587
- Base.connection.select_values(table.project(table['version'])).map{ |v| v.to_i }.sort
1023
+ def schema_migrations_table_name
1024
+ SchemaMigration.table_name
588
1025
  end
589
1026
 
590
- def current_version
591
- sm_table = schema_migrations_table_name
592
- if Base.connection.table_exists?(sm_table)
593
- get_all_versions.max || 0
594
- else
595
- 0
1027
+ def get_all_versions(connection = Base.connection)
1028
+ ActiveSupport::Deprecation.silence do
1029
+ if connection.table_exists?(schema_migrations_table_name)
1030
+ SchemaMigration.all.map { |x| x.version.to_i }.sort
1031
+ else
1032
+ []
1033
+ end
596
1034
  end
597
1035
  end
598
1036
 
599
- def proper_table_name(name)
600
- # Use the Active Record objects own table_name, or pre/suffix from ActiveRecord::Base if name is a symbol/string
601
- name.table_name rescue "#{ActiveRecord::Base.table_name_prefix}#{name}#{ActiveRecord::Base.table_name_suffix}"
1037
+ def current_version(connection = Base.connection)
1038
+ get_all_versions(connection).max || 0
1039
+ end
1040
+
1041
+ def needs_migration?(connection = Base.connection)
1042
+ (migrations(migrations_paths).collect(&:version) - get_all_versions(connection)).size > 0
1043
+ end
1044
+
1045
+ def any_migrations?
1046
+ migrations(migrations_paths).any?
1047
+ end
1048
+
1049
+ def last_migration #:nodoc:
1050
+ migrations(migrations_paths).last || NullMigration.new
602
1051
  end
603
1052
 
604
1053
  def migrations_paths
605
1054
  @migrations_paths ||= ['db/migrate']
606
- # just to not break things if someone uses: migration_path = some_string
607
- Array.wrap(@migrations_paths)
1055
+ # just to not break things if someone uses: migrations_path = some_string
1056
+ Array(@migrations_paths)
608
1057
  end
609
1058
 
610
- def migrations_path
611
- migrations_paths.first
1059
+ def match_to_migration_filename?(filename) # :nodoc:
1060
+ File.basename(filename) =~ Migration::MigrationFilenameRegexp
612
1061
  end
613
1062
 
614
- def migrations(paths, *args)
615
- if args.empty?
616
- subdirectories = true
617
- else
618
- subdirectories = args.first
619
- ActiveSupport::Deprecation.warn "The `subdirectories` argument to `migrations` is deprecated"
620
- end
621
-
622
- paths = Array.wrap(paths)
1063
+ def parse_migration_filename(filename) # :nodoc:
1064
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
1065
+ end
623
1066
 
624
- glob = subdirectories ? "**/" : ""
625
- files = Dir[*paths.map { |p| "#{p}/#{glob}[0-9]*_*.rb" }]
1067
+ def migrations(paths)
1068
+ paths = Array(paths)
626
1069
 
627
- seen = Hash.new false
1070
+ files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
628
1071
 
629
1072
  migrations = files.map do |file|
630
- version, name, scope = file.scan(/([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
631
-
1073
+ version, name, scope = parse_migration_filename(file)
632
1074
  raise IllegalMigrationNameError.new(file) unless version
633
1075
  version = version.to_i
634
1076
  name = name.camelize
635
1077
 
636
- raise DuplicateMigrationVersionError.new(version) if seen[version]
637
- raise DuplicateMigrationNameError.new(name) if seen[name]
638
-
639
- seen[version] = seen[name] = true
640
-
641
1078
  MigrationProxy.new(name, version, file, scope)
642
1079
  end
643
1080
 
@@ -647,7 +1084,7 @@ module ActiveRecord
647
1084
  private
648
1085
 
649
1086
  def move(direction, migrations_paths, steps)
650
- migrator = self.new(direction, migrations_paths)
1087
+ migrator = new(direction, migrations(migrations_paths))
651
1088
  start_index = migrator.migrations.index(migrator.current_migration)
652
1089
 
653
1090
  if start_index
@@ -658,124 +1095,215 @@ module ActiveRecord
658
1095
  end
659
1096
  end
660
1097
 
661
- def initialize(direction, migrations_paths, target_version = nil)
1098
+ def initialize(direction, migrations, target_version = nil)
662
1099
  raise StandardError.new("This database does not yet support migrations") unless Base.connection.supports_migrations?
1100
+
1101
+ @direction = direction
1102
+ @target_version = target_version
1103
+ @migrated_versions = nil
1104
+ @migrations = migrations
1105
+
1106
+ validate(@migrations)
1107
+
663
1108
  Base.connection.initialize_schema_migrations_table
664
- @direction, @migrations_paths, @target_version = direction, migrations_paths, target_version
1109
+ Base.connection.initialize_internal_metadata_table
665
1110
  end
666
1111
 
667
1112
  def current_version
668
- migrated.last || 0
1113
+ migrated.max || 0
669
1114
  end
670
1115
 
671
1116
  def current_migration
672
1117
  migrations.detect { |m| m.version == current_version }
673
1118
  end
1119
+ alias :current :current_migration
674
1120
 
675
1121
  def run
676
- target = migrations.detect { |m| m.version == @target_version }
677
- raise UnknownMigrationVersionError.new(@target_version) if target.nil?
678
- unless (up? && migrated.include?(target.version.to_i)) || (down? && !migrated.include?(target.version.to_i))
679
- target.migrate(@direction)
680
- record_version_state_after_migrating(target.version)
1122
+ if use_advisory_lock?
1123
+ with_advisory_lock { run_without_lock }
1124
+ else
1125
+ run_without_lock
681
1126
  end
682
1127
  end
683
1128
 
684
- def migrate(&block)
685
- current = migrations.detect { |m| m.version == current_version }
686
- target = migrations.detect { |m| m.version == @target_version }
687
-
688
- if target.nil? && @target_version && @target_version > 0
689
- raise UnknownMigrationVersionError.new(@target_version)
1129
+ def migrate
1130
+ if use_advisory_lock?
1131
+ with_advisory_lock { migrate_without_lock }
1132
+ else
1133
+ migrate_without_lock
690
1134
  end
1135
+ end
691
1136
 
692
- start = up? ? 0 : (migrations.index(current) || 0)
693
- finish = migrations.index(target) || migrations.size - 1
1137
+ def runnable
694
1138
  runnable = migrations[start..finish]
1139
+ if up?
1140
+ runnable.reject { |m| ran?(m) }
1141
+ else
1142
+ # skip the last migration if we're headed down, but not ALL the way down
1143
+ runnable.pop if target
1144
+ runnable.find_all { |m| ran?(m) }
1145
+ end
1146
+ end
695
1147
 
696
- # skip the last migration if we're headed down, but not ALL the way down
697
- runnable.pop if down? && target
1148
+ def migrations
1149
+ down? ? @migrations.reverse : @migrations.sort_by(&:version)
1150
+ end
698
1151
 
699
- ran = []
700
- runnable.each do |migration|
701
- if block && !block.call(migration)
702
- next
703
- end
1152
+ def pending_migrations
1153
+ already_migrated = migrated
1154
+ migrations.reject { |m| already_migrated.include?(m.version) }
1155
+ end
704
1156
 
705
- Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1157
+ def migrated
1158
+ @migrated_versions || load_migrated
1159
+ end
706
1160
 
707
- seen = migrated.include?(migration.version.to_i)
1161
+ def load_migrated
1162
+ @migrated_versions = Set.new(self.class.get_all_versions)
1163
+ end
708
1164
 
709
- # On our way up, we skip migrating the ones we've already migrated
710
- next if up? && seen
1165
+ private
711
1166
 
712
- # On our way down, we skip reverting the ones we've never migrated
713
- if down? && !seen
714
- migration.announce 'never migrated, skipping'; migration.write
715
- next
716
- end
1167
+ # Used for running a specific migration.
1168
+ def run_without_lock
1169
+ migration = migrations.detect { |m| m.version == @target_version }
1170
+ raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1171
+ execute_migration_in_transaction(migration, @direction)
717
1172
 
718
- begin
719
- ddl_transaction do
720
- migration.migrate(@direction)
721
- record_version_state_after_migrating(migration.version)
722
- end
723
- ran << migration
724
- rescue => e
725
- canceled_msg = Base.connection.supports_ddl_transactions? ? "this and " : ""
726
- raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
727
- end
728
- end
729
- ran
1173
+ record_environment
730
1174
  end
731
1175
 
732
- def migrations
733
- @migrations ||= begin
734
- migrations = self.class.migrations(@migrations_paths)
735
- down? ? migrations.reverse : migrations
1176
+ # Used for running multiple migrations up to or down to a certain value.
1177
+ def migrate_without_lock
1178
+ if invalid_target?
1179
+ raise UnknownMigrationVersionError.new(@target_version)
736
1180
  end
1181
+
1182
+ runnable.each do |migration|
1183
+ execute_migration_in_transaction(migration, @direction)
1184
+ end
1185
+
1186
+ record_environment
737
1187
  end
738
1188
 
739
- def pending_migrations
740
- already_migrated = migrated
741
- migrations.reject { |m| already_migrated.include?(m.version.to_i) }
1189
+ # Stores the current environment in the database.
1190
+ def record_environment
1191
+ return if down?
1192
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
742
1193
  end
743
1194
 
744
- def migrated
745
- @migrated_versions ||= self.class.get_all_versions
1195
+ def ran?(migration)
1196
+ migrated.include?(migration.version.to_i)
746
1197
  end
747
1198
 
748
- private
749
- def record_version_state_after_migrating(version)
750
- table = Arel::Table.new(self.class.schema_migrations_table_name)
751
-
752
- @migrated_versions ||= []
753
- if down?
754
- @migrated_versions.delete(version)
755
- stmt = table.where(table["version"].eq(version.to_s)).compile_delete
756
- Base.connection.delete stmt
757
- else
758
- @migrated_versions.push(version).sort!
759
- stmt = table.compile_insert table["version"] => version.to_s
760
- Base.connection.insert stmt
761
- end
762
- end
1199
+ # Return true if a valid version is not provided.
1200
+ def invalid_target?
1201
+ !target && @target_version && @target_version > 0
1202
+ end
1203
+
1204
+ def execute_migration_in_transaction(migration, direction)
1205
+ return if down? && !migrated.include?(migration.version.to_i)
1206
+ return if up? && migrated.include?(migration.version.to_i)
763
1207
 
764
- def up?
765
- @direction == :up
1208
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1209
+
1210
+ ddl_transaction(migration) do
1211
+ migration.migrate(direction)
1212
+ record_version_state_after_migrating(migration.version)
766
1213
  end
1214
+ rescue => e
1215
+ msg = "An error has occurred, "
1216
+ msg << "this and " if use_transaction?(migration)
1217
+ msg << "all later migrations canceled:\n\n#{e}"
1218
+ raise StandardError, msg, e.backtrace
1219
+ end
767
1220
 
768
- def down?
769
- @direction == :down
1221
+ def target
1222
+ migrations.detect { |m| m.version == @target_version }
1223
+ end
1224
+
1225
+ def finish
1226
+ migrations.index(target) || migrations.size - 1
1227
+ end
1228
+
1229
+ def start
1230
+ up? ? 0 : (migrations.index(current) || 0)
1231
+ end
1232
+
1233
+ def validate(migrations)
1234
+ name ,= migrations.group_by(&:name).find { |_,v| v.length > 1 }
1235
+ raise DuplicateMigrationNameError.new(name) if name
1236
+
1237
+ version ,= migrations.group_by(&:version).find { |_,v| v.length > 1 }
1238
+ raise DuplicateMigrationVersionError.new(version) if version
1239
+ end
1240
+
1241
+ def record_version_state_after_migrating(version)
1242
+ if down?
1243
+ migrated.delete(version)
1244
+ ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
1245
+ else
1246
+ migrated << version
1247
+ ActiveRecord::SchemaMigration.create!(version: version.to_s)
770
1248
  end
1249
+ end
771
1250
 
772
- # Wrap the migration in a transaction only if supported by the adapter.
773
- def ddl_transaction(&block)
774
- if Base.connection.supports_ddl_transactions?
775
- Base.transaction { block.call }
776
- else
777
- block.call
778
- end
1251
+ def self.last_stored_environment
1252
+ return nil if current_version == 0
1253
+ raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1254
+
1255
+ environment = ActiveRecord::InternalMetadata[:environment]
1256
+ raise NoEnvironmentInSchemaError unless environment
1257
+ environment
1258
+ end
1259
+
1260
+ def self.current_environment
1261
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1262
+ end
1263
+
1264
+ def self.protected_environment?
1265
+ ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1266
+ end
1267
+
1268
+ def up?
1269
+ @direction == :up
1270
+ end
1271
+
1272
+ def down?
1273
+ @direction == :down
1274
+ end
1275
+
1276
+ # Wrap the migration in a transaction only if supported by the adapter.
1277
+ def ddl_transaction(migration)
1278
+ if use_transaction?(migration)
1279
+ Base.transaction { yield }
1280
+ else
1281
+ yield
779
1282
  end
1283
+ end
1284
+
1285
+ def use_transaction?(migration)
1286
+ !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1287
+ end
1288
+
1289
+ def use_advisory_lock?
1290
+ Base.connection.supports_advisory_locks?
1291
+ end
1292
+
1293
+ def with_advisory_lock
1294
+ lock_id = generate_migrator_advisory_lock_id
1295
+ got_lock = Base.connection.get_advisory_lock(lock_id)
1296
+ raise ConcurrentMigrationError unless got_lock
1297
+ load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1298
+ yield
1299
+ ensure
1300
+ Base.connection.release_advisory_lock(lock_id) if got_lock
1301
+ end
1302
+
1303
+ MIGRATOR_SALT = 2053462845
1304
+ def generate_migrator_advisory_lock_id
1305
+ db_name_hash = Zlib.crc32(Base.connection.current_database)
1306
+ MIGRATOR_SALT * db_name_hash
1307
+ end
780
1308
  end
781
1309
  end