activerecord 4.2.11.3 → 5.0.0.beta1

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 (229) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +1029 -1349
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -7
  5. data/examples/performance.rb +2 -2
  6. data/lib/active_record.rb +7 -3
  7. data/lib/active_record/aggregations.rb +35 -25
  8. data/lib/active_record/association_relation.rb +2 -2
  9. data/lib/active_record/associations.rb +305 -204
  10. data/lib/active_record/associations/alias_tracker.rb +19 -16
  11. data/lib/active_record/associations/association.rb +10 -8
  12. data/lib/active_record/associations/association_scope.rb +73 -102
  13. data/lib/active_record/associations/belongs_to_association.rb +20 -32
  14. data/lib/active_record/associations/builder/association.rb +28 -34
  15. data/lib/active_record/associations/builder/belongs_to.rb +41 -18
  16. data/lib/active_record/associations/builder/collection_association.rb +8 -24
  17. data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +11 -11
  18. data/lib/active_record/associations/builder/has_many.rb +4 -4
  19. data/lib/active_record/associations/builder/has_one.rb +10 -5
  20. data/lib/active_record/associations/builder/singular_association.rb +2 -9
  21. data/lib/active_record/associations/collection_association.rb +40 -43
  22. data/lib/active_record/associations/collection_proxy.rb +55 -29
  23. data/lib/active_record/associations/foreign_association.rb +1 -1
  24. data/lib/active_record/associations/has_many_association.rb +20 -71
  25. data/lib/active_record/associations/has_many_through_association.rb +8 -52
  26. data/lib/active_record/associations/has_one_association.rb +12 -5
  27. data/lib/active_record/associations/join_dependency.rb +28 -18
  28. data/lib/active_record/associations/join_dependency/join_association.rb +13 -12
  29. data/lib/active_record/associations/preloader.rb +13 -4
  30. data/lib/active_record/associations/preloader/association.rb +45 -51
  31. data/lib/active_record/associations/preloader/collection_association.rb +0 -6
  32. data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
  33. data/lib/active_record/associations/preloader/has_one.rb +0 -8
  34. data/lib/active_record/associations/preloader/through_association.rb +5 -4
  35. data/lib/active_record/associations/singular_association.rb +6 -0
  36. data/lib/active_record/associations/through_association.rb +11 -3
  37. data/lib/active_record/attribute.rb +61 -17
  38. data/lib/active_record/attribute/user_provided_default.rb +23 -0
  39. data/lib/active_record/attribute_assignment.rb +27 -140
  40. data/lib/active_record/attribute_decorators.rb +6 -5
  41. data/lib/active_record/attribute_methods.rb +79 -26
  42. data/lib/active_record/attribute_methods/before_type_cast.rb +1 -1
  43. data/lib/active_record/attribute_methods/dirty.rb +46 -86
  44. data/lib/active_record/attribute_methods/primary_key.rb +2 -2
  45. data/lib/active_record/attribute_methods/query.rb +2 -2
  46. data/lib/active_record/attribute_methods/read.rb +26 -42
  47. data/lib/active_record/attribute_methods/serialization.rb +13 -16
  48. data/lib/active_record/attribute_methods/time_zone_conversion.rb +42 -9
  49. data/lib/active_record/attribute_methods/write.rb +13 -24
  50. data/lib/active_record/attribute_mutation_tracker.rb +70 -0
  51. data/lib/active_record/attribute_set.rb +30 -3
  52. data/lib/active_record/attribute_set/builder.rb +6 -4
  53. data/lib/active_record/attributes.rb +194 -81
  54. data/lib/active_record/autosave_association.rb +33 -15
  55. data/lib/active_record/base.rb +30 -18
  56. data/lib/active_record/callbacks.rb +36 -40
  57. data/lib/active_record/coders/yaml_column.rb +20 -8
  58. data/lib/active_record/collection_cache_key.rb +31 -0
  59. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +431 -122
  60. data/lib/active_record/connection_adapters/abstract/database_limits.rb +3 -3
  61. data/lib/active_record/connection_adapters/abstract/database_statements.rb +40 -22
  62. data/lib/active_record/connection_adapters/abstract/quoting.rb +62 -8
  63. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +46 -38
  64. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +229 -185
  65. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +52 -13
  66. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +275 -115
  67. data/lib/active_record/connection_adapters/abstract/transaction.rb +32 -33
  68. data/lib/active_record/connection_adapters/abstract_adapter.rb +83 -32
  69. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +384 -221
  70. data/lib/active_record/connection_adapters/column.rb +27 -41
  71. data/lib/active_record/connection_adapters/connection_specification.rb +2 -21
  72. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +22 -0
  73. data/lib/active_record/connection_adapters/mysql/schema_creation.rb +57 -0
  74. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +69 -0
  75. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +59 -0
  76. data/lib/active_record/connection_adapters/mysql2_adapter.rb +22 -101
  77. data/lib/active_record/connection_adapters/postgresql/column.rb +6 -10
  78. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +3 -3
  79. data/lib/active_record/connection_adapters/postgresql/oid.rb +1 -6
  80. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +23 -57
  81. data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +2 -2
  82. data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +1 -1
  83. data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +1 -1
  84. data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +7 -22
  85. data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +3 -3
  86. data/lib/active_record/connection_adapters/postgresql/oid/json.rb +1 -26
  87. data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +2 -2
  88. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
  89. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +4 -4
  90. data/lib/active_record/connection_adapters/postgresql/oid/rails_5_1_point.rb +50 -0
  91. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +23 -16
  92. data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +0 -4
  93. data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +2 -2
  94. data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +1 -1
  95. data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +1 -1
  96. data/lib/active_record/connection_adapters/postgresql/quoting.rb +18 -11
  97. data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +29 -10
  98. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +107 -79
  99. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +54 -0
  100. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +174 -128
  101. data/lib/active_record/connection_adapters/postgresql/type_metadata.rb +35 -0
  102. data/lib/active_record/connection_adapters/postgresql_adapter.rb +184 -112
  103. data/lib/active_record/connection_adapters/schema_cache.rb +36 -23
  104. data/lib/active_record/connection_adapters/sql_type_metadata.rb +32 -0
  105. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +15 -0
  106. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +134 -110
  107. data/lib/active_record/connection_adapters/statement_pool.rb +28 -11
  108. data/lib/active_record/connection_handling.rb +5 -5
  109. data/lib/active_record/core.rb +72 -104
  110. data/lib/active_record/counter_cache.rb +9 -20
  111. data/lib/active_record/dynamic_matchers.rb +1 -20
  112. data/lib/active_record/enum.rb +110 -76
  113. data/lib/active_record/errors.rb +72 -47
  114. data/lib/active_record/explain_registry.rb +1 -1
  115. data/lib/active_record/explain_subscriber.rb +1 -1
  116. data/lib/active_record/fixture_set/file.rb +19 -4
  117. data/lib/active_record/fixtures.rb +76 -40
  118. data/lib/active_record/gem_version.rb +4 -4
  119. data/lib/active_record/inheritance.rb +27 -40
  120. data/lib/active_record/integration.rb +4 -4
  121. data/lib/active_record/legacy_yaml_adapter.rb +18 -2
  122. data/lib/active_record/locale/en.yml +3 -2
  123. data/lib/active_record/locking/optimistic.rb +10 -14
  124. data/lib/active_record/locking/pessimistic.rb +1 -1
  125. data/lib/active_record/log_subscriber.rb +40 -22
  126. data/lib/active_record/migration.rb +304 -133
  127. data/lib/active_record/migration/command_recorder.rb +59 -18
  128. data/lib/active_record/migration/compatibility.rb +90 -0
  129. data/lib/active_record/model_schema.rb +92 -40
  130. data/lib/active_record/nested_attributes.rb +45 -34
  131. data/lib/active_record/null_relation.rb +15 -7
  132. data/lib/active_record/persistence.rb +112 -72
  133. data/lib/active_record/querying.rb +6 -5
  134. data/lib/active_record/railtie.rb +20 -13
  135. data/lib/active_record/railties/controller_runtime.rb +1 -1
  136. data/lib/active_record/railties/databases.rake +47 -38
  137. data/lib/active_record/readonly_attributes.rb +1 -1
  138. data/lib/active_record/reflection.rb +182 -57
  139. data/lib/active_record/relation.rb +152 -100
  140. data/lib/active_record/relation/batches.rb +133 -33
  141. data/lib/active_record/relation/batches/batch_enumerator.rb +67 -0
  142. data/lib/active_record/relation/calculations.rb +80 -101
  143. data/lib/active_record/relation/delegation.rb +6 -19
  144. data/lib/active_record/relation/finder_methods.rb +58 -46
  145. data/lib/active_record/relation/from_clause.rb +32 -0
  146. data/lib/active_record/relation/merger.rb +13 -42
  147. data/lib/active_record/relation/predicate_builder.rb +99 -105
  148. data/lib/active_record/relation/predicate_builder/array_handler.rb +11 -16
  149. data/lib/active_record/relation/predicate_builder/association_query_handler.rb +78 -0
  150. data/lib/active_record/relation/predicate_builder/base_handler.rb +17 -0
  151. data/lib/active_record/relation/predicate_builder/basic_object_handler.rb +17 -0
  152. data/lib/active_record/relation/predicate_builder/class_handler.rb +27 -0
  153. data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -0
  154. data/lib/active_record/relation/query_attribute.rb +19 -0
  155. data/lib/active_record/relation/query_methods.rb +274 -238
  156. data/lib/active_record/relation/record_fetch_warning.rb +51 -0
  157. data/lib/active_record/relation/spawn_methods.rb +3 -6
  158. data/lib/active_record/relation/where_clause.rb +173 -0
  159. data/lib/active_record/relation/where_clause_factory.rb +37 -0
  160. data/lib/active_record/result.rb +4 -3
  161. data/lib/active_record/runtime_registry.rb +1 -1
  162. data/lib/active_record/sanitization.rb +94 -65
  163. data/lib/active_record/schema.rb +23 -22
  164. data/lib/active_record/schema_dumper.rb +33 -22
  165. data/lib/active_record/schema_migration.rb +10 -4
  166. data/lib/active_record/scoping.rb +17 -6
  167. data/lib/active_record/scoping/default.rb +19 -6
  168. data/lib/active_record/scoping/named.rb +39 -28
  169. data/lib/active_record/secure_token.rb +38 -0
  170. data/lib/active_record/serialization.rb +2 -4
  171. data/lib/active_record/statement_cache.rb +15 -13
  172. data/lib/active_record/store.rb +8 -3
  173. data/lib/active_record/suppressor.rb +54 -0
  174. data/lib/active_record/table_metadata.rb +64 -0
  175. data/lib/active_record/tasks/database_tasks.rb +30 -40
  176. data/lib/active_record/tasks/mysql_database_tasks.rb +7 -15
  177. data/lib/active_record/tasks/postgresql_database_tasks.rb +11 -2
  178. data/lib/active_record/tasks/sqlite_database_tasks.rb +5 -1
  179. data/lib/active_record/timestamp.rb +16 -9
  180. data/lib/active_record/touch_later.rb +58 -0
  181. data/lib/active_record/transactions.rb +138 -56
  182. data/lib/active_record/type.rb +66 -17
  183. data/lib/active_record/type/adapter_specific_registry.rb +130 -0
  184. data/lib/active_record/type/date.rb +2 -45
  185. data/lib/active_record/type/date_time.rb +2 -49
  186. data/lib/active_record/type/internal/abstract_json.rb +33 -0
  187. data/lib/active_record/type/internal/timezone.rb +15 -0
  188. data/lib/active_record/type/serialized.rb +9 -14
  189. data/lib/active_record/type/time.rb +3 -21
  190. data/lib/active_record/type/type_map.rb +4 -4
  191. data/lib/active_record/type_caster.rb +7 -0
  192. data/lib/active_record/type_caster/connection.rb +29 -0
  193. data/lib/active_record/type_caster/map.rb +19 -0
  194. data/lib/active_record/validations.rb +33 -32
  195. data/lib/active_record/validations/absence.rb +24 -0
  196. data/lib/active_record/validations/associated.rb +10 -3
  197. data/lib/active_record/validations/length.rb +36 -0
  198. data/lib/active_record/validations/presence.rb +12 -12
  199. data/lib/active_record/validations/uniqueness.rb +24 -21
  200. data/lib/rails/generators/active_record/migration.rb +7 -0
  201. data/lib/rails/generators/active_record/migration/migration_generator.rb +7 -4
  202. data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +8 -3
  203. data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -1
  204. data/lib/rails/generators/active_record/model/model_generator.rb +21 -15
  205. data/lib/rails/generators/active_record/model/templates/model.rb +3 -0
  206. metadata +50 -35
  207. data/lib/active_record/connection_adapters/mysql_adapter.rb +0 -498
  208. data/lib/active_record/connection_adapters/postgresql/array_parser.rb +0 -93
  209. data/lib/active_record/connection_adapters/postgresql/oid/date.rb +0 -11
  210. data/lib/active_record/connection_adapters/postgresql/oid/float.rb +0 -21
  211. data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +0 -13
  212. data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +0 -11
  213. data/lib/active_record/connection_adapters/postgresql/oid/time.rb +0 -11
  214. data/lib/active_record/serializers/xml_serializer.rb +0 -193
  215. data/lib/active_record/type/big_integer.rb +0 -13
  216. data/lib/active_record/type/binary.rb +0 -50
  217. data/lib/active_record/type/boolean.rb +0 -31
  218. data/lib/active_record/type/decimal.rb +0 -64
  219. data/lib/active_record/type/decimal_without_scale.rb +0 -11
  220. data/lib/active_record/type/decorator.rb +0 -14
  221. data/lib/active_record/type/float.rb +0 -19
  222. data/lib/active_record/type/integer.rb +0 -59
  223. data/lib/active_record/type/mutable.rb +0 -16
  224. data/lib/active_record/type/numeric.rb +0 -36
  225. data/lib/active_record/type/string.rb +0 -40
  226. data/lib/active_record/type/text.rb +0 -11
  227. data/lib/active_record/type/time_value.rb +0 -38
  228. data/lib/active_record/type/unsigned_integer.rb +0 -15
  229. data/lib/active_record/type/value.rb +0 -110
@@ -10,12 +10,12 @@ module ActiveRecord
10
10
  # Indicates the format used to generate the timestamp in the cache key.
11
11
  # Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
12
12
  #
13
- # This is +:nsec+, by default.
13
+ # This is +:usec+, by default.
14
14
  class_attribute :cache_timestamp_format, :instance_writer => false
15
- self.cache_timestamp_format = :nsec
15
+ self.cache_timestamp_format = :usec
16
16
  end
17
17
 
18
- # Returns a String, which Action Pack uses for constructing an URL to this
18
+ # Returns a String, which Action Pack uses for constructing a URL to this
19
19
  # object. The default implementation returns this record's id as a String,
20
20
  # or nil if this record's unsaved.
21
21
  #
@@ -84,7 +84,7 @@ module ActiveRecord
84
84
  # Values longer than 20 characters will be truncated. The value
85
85
  # is truncated word by word.
86
86
  #
87
- # user = User.find_by(name: 'David HeinemeierHansson')
87
+ # user = User.find_by(name: 'David Heinemeier Hansson')
88
88
  # user.id # => 125
89
89
  # user_path(user) # => "/users/125-david"
90
90
  #
@@ -4,16 +4,32 @@ module ActiveRecord
4
4
  return coder unless coder.is_a?(Psych::Coder)
5
5
 
6
6
  case coder["active_record_yaml_version"]
7
- when 0 then coder
7
+ when 1 then coder
8
8
  else
9
9
  if coder["attributes"].is_a?(AttributeSet)
10
- coder
10
+ Rails420.convert(klass, coder)
11
11
  else
12
12
  Rails41.convert(klass, coder)
13
13
  end
14
14
  end
15
15
  end
16
16
 
17
+ module Rails420
18
+ def self.convert(klass, coder)
19
+ attribute_set = coder["attributes"]
20
+
21
+ klass.attribute_names.each do |attr_name|
22
+ attribute = attribute_set[attr_name]
23
+ if attribute.type.is_a?(Delegator)
24
+ type_from_klass = klass.type_for_attribute(attr_name)
25
+ attribute_set[attr_name] = attribute.with_type(type_from_klass)
26
+ end
27
+ end
28
+
29
+ coder
30
+ end
31
+ end
32
+
17
33
  module Rails41
18
34
  def self.convert(klass, coder)
19
35
  attributes = klass.attributes_builder
@@ -7,6 +7,7 @@ en:
7
7
  # Default error messages
8
8
  errors:
9
9
  messages:
10
+ required: "must exist"
10
11
  taken: "has already been taken"
11
12
 
12
13
  # Active Record models configuration
@@ -15,8 +16,8 @@ en:
15
16
  messages:
16
17
  record_invalid: "Validation failed: %{errors}"
17
18
  restrict_dependent_destroy:
18
- one: "Cannot delete record because a dependent %{record} exists"
19
- many: "Cannot delete record because dependent %{record} exist"
19
+ has_one: "Cannot delete record because a dependent %{record} exists"
20
+ has_many: "Cannot delete record because dependent %{record} exist"
20
21
  # Append your own errors here or at the model/attributes scope.
21
22
 
22
23
  # You can define own errors for models or model attributes.
@@ -11,7 +11,7 @@ module ActiveRecord
11
11
  #
12
12
  # == Usage
13
13
  #
14
- # Active Records support optimistic locking if the field +lock_version+ is present. Each update to the
14
+ # Active Record supports optimistic locking if the +lock_version+ field is present. Each update to the
15
15
  # record increments the +lock_version+ column and the locking facilities ensure that records instantiated twice
16
16
  # will let the last one saved raise a +StaleObjectError+ if the first was also updated. Example:
17
17
  #
@@ -22,7 +22,7 @@ module ActiveRecord
22
22
  # p1.save
23
23
  #
24
24
  # p2.first_name = "should fail"
25
- # p2.save # Raises a ActiveRecord::StaleObjectError
25
+ # p2.save # Raises an ActiveRecord::StaleObjectError
26
26
  #
27
27
  # Optimistic locking will also check for stale data when objects are destroyed. Example:
28
28
  #
@@ -32,7 +32,7 @@ module ActiveRecord
32
32
  # p1.first_name = "Michael"
33
33
  # p1.save
34
34
  #
35
- # p2.destroy # Raises a ActiveRecord::StaleObjectError
35
+ # p2.destroy # Raises an ActiveRecord::StaleObjectError
36
36
  #
37
37
  # You're then responsible for dealing with the conflict by rescuing the exception and either rolling back, merging,
38
38
  # or otherwise apply the business logic needed to resolve the conflict.
@@ -93,9 +93,9 @@ module ActiveRecord
93
93
  self.class.primary_key => id,
94
94
  lock_col => previous_lock_value,
95
95
  ).update_all(
96
- Hash[attributes_for_update(attribute_names).map do |name|
96
+ attributes_for_update(attribute_names).map do |name|
97
97
  [name, _read_attribute(name)]
98
- end]
98
+ end.to_h
99
99
  )
100
100
 
101
101
  unless affected_rows == 1
@@ -125,12 +125,8 @@ module ActiveRecord
125
125
  relation = super
126
126
 
127
127
  if locking_enabled?
128
- column_name = self.class.locking_column
129
- column = self.class.columns_hash[column_name]
130
- substitute = self.class.connection.substitute_at(column)
131
-
132
- relation = relation.where(self.class.arel_table[column_name].eq(substitute))
133
- relation.bind_values << [column, self[column_name].to_i]
128
+ locking_column = self.class.locking_column
129
+ relation = relation.where(locking_column => _read_attribute(locking_column))
134
130
  end
135
131
 
136
132
  relation
@@ -148,7 +144,7 @@ module ActiveRecord
148
144
 
149
145
  # Set the column to use for optimistic locking. Defaults to +lock_version+.
150
146
  def locking_column=(value)
151
- clear_caches_calculated_from_columns
147
+ reload_schema_from_cache
152
148
  @locking_column = value.to_s
153
149
  end
154
150
 
@@ -188,8 +184,8 @@ module ActiveRecord
188
184
  end
189
185
  end
190
186
 
191
- class LockingType < SimpleDelegator # :nodoc:
192
- def type_cast_from_database(value)
187
+ class LockingType < DelegateClass(Type::Value) # :nodoc:
188
+ def deserialize(value)
193
189
  # `nil` *should* be changed to 0
194
190
  super.to_i
195
191
  end
@@ -51,7 +51,7 @@ module ActiveRecord
51
51
  # end
52
52
  #
53
53
  # Database-specific information on row locking:
54
- # MySQL: http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
54
+ # MySQL: http://dev.mysql.com/doc/refman/5.7/en/innodb-locking-reads.html
55
55
  # PostgreSQL: http://www.postgresql.org/docs/current/interactive/sql-select.html#SQL-FOR-UPDATE-SHARE
56
56
  module Pessimistic
57
57
  # Obtain a row lock on this record. Reloads the record to obtain the requested
@@ -20,24 +20,21 @@ module ActiveRecord
20
20
  @odd = false
21
21
  end
22
22
 
23
- def render_bind(column, value)
24
- if column
25
- if column.binary?
26
- # This specifically deals with the PG adapter that casts bytea columns into a Hash.
27
- value = value[:value] if value.is_a?(Hash)
28
- value = value ? "<#{value.bytesize} bytes of binary data>" : "<NULL binary data>"
29
- end
30
-
31
- [column.name, value]
23
+ def render_bind(attribute)
24
+ value = if attribute.type.binary? && attribute.value
25
+ "<#{attribute.value.bytesize} bytes of binary data>"
32
26
  else
33
- [nil, value]
27
+ attribute.value_for_database
34
28
  end
29
+
30
+ [attribute.name, value]
35
31
  end
36
32
 
37
33
  def sql(event)
38
- self.class.runtime += event.duration
39
34
  return unless logger.debug?
40
35
 
36
+ self.class.runtime += event.duration
37
+
41
38
  payload = event.payload
42
39
 
43
40
  return if IGNORE_PAYLOAD_NAMES.include?(payload[:name])
@@ -47,23 +44,44 @@ module ActiveRecord
47
44
  binds = nil
48
45
 
49
46
  unless (payload[:binds] || []).empty?
50
- binds = " " + payload[:binds].map { |col,v|
51
- render_bind(col, v)
52
- }.inspect
47
+ binds = " " + payload[:binds].map { |attr| render_bind(attr) }.inspect
53
48
  end
54
49
 
55
- if odd?
56
- name = color(name, CYAN, true)
57
- sql = color(sql, nil, true)
58
- else
59
- name = color(name, MAGENTA, true)
60
- end
50
+ name = colorize_payload_name(name, payload[:name])
51
+ sql = color(sql, sql_color(sql), true)
61
52
 
62
53
  debug " #{name} #{sql}#{binds}"
63
54
  end
64
55
 
65
- def odd?
66
- @odd = !@odd
56
+ private
57
+
58
+ def colorize_payload_name(name, payload_name)
59
+ if payload_name.blank? || payload_name == "SQL" # SQL vs Model Load/Exists
60
+ color(name, MAGENTA, true)
61
+ else
62
+ color(name, CYAN, true)
63
+ end
64
+ end
65
+
66
+ def sql_color(sql)
67
+ case sql
68
+ when /\A\s*rollback/mi
69
+ RED
70
+ when /\s*.*?select .*for update/mi, /\A\s*lock/mi
71
+ WHITE
72
+ when /\A\s*select/i
73
+ BLUE
74
+ when /\A\s*insert/i
75
+ GREEN
76
+ when /\A\s*update/i
77
+ YELLOW
78
+ when /\A\s*delete/i
79
+ RED
80
+ when /transaction\s*\Z/i
81
+ CYAN
82
+ else
83
+ MAGENTA
84
+ end
67
85
  end
68
86
 
69
87
  def logger
@@ -9,44 +9,140 @@ module ActiveRecord
9
9
  end
10
10
  end
11
11
 
12
- # Exception that can be raised to stop migrations from going backwards.
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
13
83
  class IrreversibleMigration < MigrationError
14
84
  end
15
85
 
16
86
  class DuplicateMigrationVersionError < MigrationError#:nodoc:
17
- def initialize(version)
18
- super("Multiple migrations have the version number #{version}")
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
19
93
  end
20
94
  end
21
95
 
22
96
  class DuplicateMigrationNameError < MigrationError#:nodoc:
23
- def initialize(name)
24
- super("Multiple migrations have the name #{name}")
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
25
103
  end
26
104
  end
27
105
 
28
106
  class UnknownMigrationVersionError < MigrationError #:nodoc:
29
- def initialize(version)
30
- super("No migration with version number #{version}")
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
31
113
  end
32
114
  end
33
115
 
34
116
  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)")
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
37
123
  end
38
124
  end
39
125
 
40
126
  class PendingMigrationError < MigrationError#:nodoc:
41
- def initialize
42
- if defined?(Rails.env)
43
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate RAILS_ENV=#{::Rails.env}")
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.")
44
132
  else
45
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rake db:migrate")
133
+ super
46
134
  end
47
135
  end
48
136
  end
49
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
+
50
146
  # = Active Record Migrations
51
147
  #
52
148
  # Migrations can manage the evolution of a schema used by several physical
@@ -59,7 +155,7 @@ module ActiveRecord
59
155
  #
60
156
  # Example of a simple migration:
61
157
  #
62
- # class AddSsl < ActiveRecord::Migration
158
+ # class AddSsl < ActiveRecord::Migration[5.0]
63
159
  # def up
64
160
  # add_column :accounts, :ssl_enabled, :boolean, default: true
65
161
  # end
@@ -79,7 +175,7 @@ module ActiveRecord
79
175
  #
80
176
  # Example of a more complex migration that also needs to initialize data:
81
177
  #
82
- # class AddSystemSettings < ActiveRecord::Migration
178
+ # class AddSystemSettings < ActiveRecord::Migration[5.0]
83
179
  # def up
84
180
  # create_table :system_settings do |t|
85
181
  # t.string :name
@@ -106,17 +202,18 @@ module ActiveRecord
106
202
  #
107
203
  # == Available transformations
108
204
  #
205
+ # === Creation
206
+ #
207
+ # * <tt>create_join_table(table_1, table_2, options)</tt>: Creates a join
208
+ # table having its name as the lexical order of the first two
209
+ # arguments. See
210
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#create_join_table for
211
+ # details.
109
212
  # * <tt>create_table(name, options)</tt>: Creates a table called +name+ and
110
213
  # makes the table object available to a block that can then add columns to it,
111
214
  # following the same format as +add_column+. See example above. The options hash
112
215
  # is for fragments like "DEFAULT CHARSET=UTF-8" that are appended to the create
113
216
  # 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
217
  # * <tt>add_column(table_name, column_name, type, options)</tt>: Adds a new column
121
218
  # to the table called +table_name+
122
219
  # named +column_name+ specified to be one of the following types:
@@ -127,21 +224,59 @@ module ActiveRecord
127
224
  # Other options include <tt>:limit</tt> and <tt>:null</tt> (e.g.
128
225
  # <tt>{ limit: 50, null: false }</tt>) -- see
129
226
  # 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+.
227
+ # * <tt>add_foreign_key(from_table, to_table, options)</tt>: Adds a new
228
+ # foreign key. +from_table+ is the table with the key column, +to_table+ contains
229
+ # the referenced primary key.
136
230
  # * <tt>add_index(table_name, column_names, options)</tt>: Adds a new index
137
231
  # with the name of the column. Other options include
138
232
  # <tt>:name</tt>, <tt>:unique</tt> (e.g.
139
233
  # <tt>{ name: 'users_name_index', unique: true }</tt>) and <tt>:order</tt>
140
234
  # (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+.
235
+ # * <tt>add_reference(:table_name, :reference_name)</tt>: Adds a new column
236
+ # +reference_name_id+ by default an integer. See
237
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#add_reference for details.
238
+ # * <tt>add_timestamps(table_name, options)</tt>: Adds timestamps (+created_at+
239
+ # and +updated_at+) columns to +table_name+.
240
+ #
241
+ # === Modification
242
+ #
243
+ # * <tt>change_column(table_name, column_name, type, options)</tt>: Changes
244
+ # the column to a different type using the same parameters as add_column.
245
+ # * <tt>change_column_default(table_name, column_name, default)</tt>: Sets a
246
+ # default value for +column_name+ definded by +default+ on +table_name+.
247
+ # * <tt>change_column_null(table_name, column_name, null, default = nil)</tt>:
248
+ # Sets or removes a +NOT NULL+ constraint on +column_name+. The +null+ flag
249
+ # indicates whether the value can be +NULL+. See
250
+ # ActiveRecord::ConnectionAdapters::SchemaStatements#change_column_null for
251
+ # details.
252
+ # * <tt>change_table(name, options)</tt>: Allows to make column alterations to
253
+ # the table called +name+. It makes the table object available to a block that
254
+ # can then add/remove columns, indexes or foreign keys to it.
255
+ # * <tt>rename_column(table_name, column_name, new_column_name)</tt>: Renames
256
+ # a column but keeps the type and content.
257
+ # * <tt>rename_index(table_name, old_name, new_name)</tt>: Renames an index.
258
+ # * <tt>rename_table(old_name, new_name)</tt>: Renames the table called +old_name+
259
+ # to +new_name+.
260
+ #
261
+ # === Deletion
262
+ #
263
+ # * <tt>drop_table(name)</tt>: Drops the table called +name+.
264
+ # * <tt>drop_join_table(table_1, table_2, options)</tt>: Drops the join table
265
+ # specified by the given arguments.
266
+ # * <tt>remove_column(table_name, column_name, type, options)</tt>: Removes the column
267
+ # named +column_name+ from the table called +table_name+.
268
+ # * <tt>remove_columns(table_name, *column_names)</tt>: Removes the given
269
+ # columns from the table definition.
270
+ # * <tt>remove_foreign_key(from_table, options_or_to_table)</tt>: Removes the
271
+ # given foreign key from the table called +table_name+.
272
+ # * <tt>remove_index(table_name, column: column_names)</tt>: Removes the index
273
+ # specified by +column_names+.
143
274
  # * <tt>remove_index(table_name, name: index_name)</tt>: Removes the index
144
275
  # specified by +index_name+.
276
+ # * <tt>remove_reference(table_name, ref_name, options)</tt>: Removes the
277
+ # reference(s) on +table_name+ specified by +ref_name+.
278
+ # * <tt>remove_timestamps(table_name, options)</tt>: Removes the timestamp
279
+ # columns (+created_at+ and +updated_at+) from the table definition.
145
280
  #
146
281
  # == Irreversible transformations
147
282
  #
@@ -165,24 +300,24 @@ module ActiveRecord
165
300
  #
166
301
  # rails generate migration add_fieldname_to_tablename fieldname:string
167
302
  #
168
- # This will generate the file <tt>timestamp_add_fieldname_to_tablename</tt>, which will look like this:
169
- # class AddFieldnameToTablename < ActiveRecord::Migration
303
+ # This will generate the file <tt>timestamp_add_fieldname_to_tablename.rb</tt>, which will look like this:
304
+ # class AddFieldnameToTablename < ActiveRecord::Migration[5.0]
170
305
  # def change
171
- # add_column :tablenames, :field, :string
306
+ # add_column :tablenames, :fieldname, :string
172
307
  # end
173
308
  # end
174
309
  #
175
310
  # 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
311
+ # <tt>rails db:migrate</tt>. This will update the database by running all of the
177
312
  # pending migrations, creating the <tt>schema_migrations</tt> table
178
313
  # (see "About the schema_migrations table" section below) if missing. It will also
179
314
  # invoke the db:schema:dump task, which will update your db/schema.rb file
180
315
  # to match the structure of your database.
181
316
  #
182
317
  # 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
318
+ # <tt>rails db:migrate VERSION=X</tt> where <tt>X</tt> is the version to which
184
319
  # 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
320
+ # wish to rollback last few migrations. <tt>rails db:migrate STEP=2</tt> will rollback
186
321
  # the latest two migrations.
187
322
  #
188
323
  # If any of the migrations throw an <tt>ActiveRecord::IrreversibleMigration</tt> exception,
@@ -197,7 +332,7 @@ module ActiveRecord
197
332
  #
198
333
  # Not all migrations change the schema. Some just fix the data:
199
334
  #
200
- # class RemoveEmptyTags < ActiveRecord::Migration
335
+ # class RemoveEmptyTags < ActiveRecord::Migration[5.0]
201
336
  # def up
202
337
  # Tag.all.each { |tag| tag.destroy if tag.pages.empty? }
203
338
  # end
@@ -210,7 +345,7 @@ module ActiveRecord
210
345
  #
211
346
  # Others remove columns when they migrate up instead of down:
212
347
  #
213
- # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration
348
+ # class RemoveUnnecessaryItemAttributes < ActiveRecord::Migration[5.0]
214
349
  # def up
215
350
  # remove_column :items, :incomplete_items_count
216
351
  # remove_column :items, :completed_items_count
@@ -224,7 +359,7 @@ module ActiveRecord
224
359
  #
225
360
  # And sometimes you need to do something in SQL not abstracted directly by migrations:
226
361
  #
227
- # class MakeJoinUnique < ActiveRecord::Migration
362
+ # class MakeJoinUnique < ActiveRecord::Migration[5.0]
228
363
  # def up
229
364
  # execute "ALTER TABLE `pages_linked_pages` ADD UNIQUE `page_id_linked_page_id` (`page_id`,`linked_page_id`)"
230
365
  # end
@@ -241,7 +376,7 @@ module ActiveRecord
241
376
  # <tt>Base#reset_column_information</tt> in order to ensure that the model has the
242
377
  # latest column data from after the new column was added. Example:
243
378
  #
244
- # class AddPeopleSalary < ActiveRecord::Migration
379
+ # class AddPeopleSalary < ActiveRecord::Migration[5.0]
245
380
  # def up
246
381
  # add_column :people, :salary, :integer
247
382
  # Person.reset_column_information
@@ -275,21 +410,6 @@ module ActiveRecord
275
410
  # The phrase "Updating salaries..." would then be printed, along with the
276
411
  # benchmark for the block when the block completes.
277
412
  #
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
413
  # == Timestamped Migrations
294
414
  #
295
415
  # By default, Rails generates migrations that look like:
@@ -314,7 +434,7 @@ module ActiveRecord
314
434
  # To define a reversible migration, define the +change+ method in your
315
435
  # migration like this:
316
436
  #
317
- # class TenderloveMigration < ActiveRecord::Migration
437
+ # class TenderloveMigration < ActiveRecord::Migration[5.0]
318
438
  # def change
319
439
  # create_table(:horses) do |t|
320
440
  # t.column :content, :text
@@ -344,7 +464,7 @@ module ActiveRecord
344
464
  # can't execute inside a transaction though, and for these situations
345
465
  # you can turn the automatic transactions off.
346
466
  #
347
- # class ChangeEnum < ActiveRecord::Migration
467
+ # class ChangeEnum < ActiveRecord::Migration[5.0]
348
468
  # disable_ddl_transaction!
349
469
  #
350
470
  # def up
@@ -356,7 +476,34 @@ module ActiveRecord
356
476
  # are in a Migration with <tt>self.disable_ddl_transaction!</tt>.
357
477
  class Migration
358
478
  autoload :CommandRecorder, 'active_record/migration/command_recorder'
479
+ autoload :Compatibility, 'active_record/migration/compatibility'
480
+
481
+ # This must be defined before the inherited hook, below
482
+ class Current < Migration # :nodoc:
483
+ end
484
+
485
+ def self.inherited(subclass) # :nodoc:
486
+ super
487
+ if subclass.superclass == Migration
488
+ subclass.include Compatibility::Legacy
489
+ end
490
+ end
491
+
492
+ def self.[](version)
493
+ version = version.to_s
494
+ name = "V#{version.tr('.', '_')}"
495
+ unless Compatibility.const_defined?(name)
496
+ versions = Compatibility.constants.grep(/\AV[0-9_]+\z/).map { |s| s.to_s.delete('V').tr('_', '.').inspect }
497
+ raise "Unknown migration version #{version.inspect}; expected one of #{versions.sort.join(', ')}"
498
+ end
499
+ Compatibility.const_get(name)
500
+ end
359
501
 
502
+ def self.current_version
503
+ Rails.version.to_f
504
+ end
505
+
506
+ MigrationFilenameRegexp = /\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/ # :nodoc:
360
507
 
361
508
  # This class is used to verify that all migrations have been run before
362
509
  # loading a web page if config.active_record.migration_error is set to :page_load
@@ -388,17 +535,22 @@ module ActiveRecord
388
535
  attr_accessor :delegate # :nodoc:
389
536
  attr_accessor :disable_ddl_transaction # :nodoc:
390
537
 
538
+ def nearest_delegate # :nodoc:
539
+ delegate || superclass.nearest_delegate
540
+ end
541
+
542
+ # Raises <tt>ActiveRecord::PendingMigrationError</tt> error if any migrations are pending.
391
543
  def check_pending!(connection = Base.connection)
392
544
  raise ActiveRecord::PendingMigrationError if ActiveRecord::Migrator.needs_migration?(connection)
393
545
  end
394
546
 
395
547
  def load_schema_if_pending!
396
548
  if ActiveRecord::Migrator.needs_migration? || !ActiveRecord::Migrator.any_migrations?
397
- # Roundrip to Rake to allow plugins to hook into database initialization.
549
+ # Roundtrip to Rake to allow plugins to hook into database initialization.
398
550
  FileUtils.cd Rails.root do
399
551
  current_config = Base.connection_config
400
552
  Base.clear_all_connections!
401
- system("bin/rake db:test:prepare")
553
+ system("bin/rails db:test:prepare")
402
554
  # Establish a new connection, the old database may be gone (db:test:prepare uses purge)
403
555
  Base.establish_connection(current_config)
404
556
  end
@@ -413,7 +565,7 @@ module ActiveRecord
413
565
  end
414
566
 
415
567
  def method_missing(name, *args, &block) # :nodoc:
416
- (delegate || superclass.delegate).send(name, *args, &block)
568
+ nearest_delegate.send(name, *args, &block)
417
569
  end
418
570
 
419
571
  def migrate(direction)
@@ -453,7 +605,7 @@ module ActiveRecord
453
605
  # and create the table 'apples' on the way up, and the reverse
454
606
  # on the way down.
455
607
  #
456
- # class FixTLMigration < ActiveRecord::Migration
608
+ # class FixTLMigration < ActiveRecord::Migration[5.0]
457
609
  # def change
458
610
  # revert do
459
611
  # create_table(:horses) do |t|
@@ -470,9 +622,9 @@ module ActiveRecord
470
622
  # Or equivalently, if +TenderloveMigration+ is defined as in the
471
623
  # documentation for Migration:
472
624
  #
473
- # require_relative '2012121212_tenderlove_migration'
625
+ # require_relative '20121212123456_tenderlove_migration'
474
626
  #
475
- # class FixupTLMigration < ActiveRecord::Migration
627
+ # class FixupTLMigration < ActiveRecord::Migration[5.0]
476
628
  # def change
477
629
  # revert TenderloveMigration
478
630
  #
@@ -486,13 +638,13 @@ module ActiveRecord
486
638
  def revert(*migration_classes)
487
639
  run(*migration_classes.reverse, revert: true) unless migration_classes.empty?
488
640
  if block_given?
489
- if @connection.respond_to? :revert
490
- @connection.revert { yield }
641
+ if connection.respond_to? :revert
642
+ connection.revert { yield }
491
643
  else
492
- recorder = CommandRecorder.new(@connection)
644
+ recorder = CommandRecorder.new(connection)
493
645
  @connection = recorder
494
646
  suppress_messages do
495
- @connection.revert { yield }
647
+ connection.revert { yield }
496
648
  end
497
649
  @connection = recorder.delegate
498
650
  recorder.commands.each do |cmd, args, block|
@@ -503,7 +655,7 @@ module ActiveRecord
503
655
  end
504
656
 
505
657
  def reverting?
506
- @connection.respond_to?(:reverting) && @connection.reverting
658
+ connection.respond_to?(:reverting) && connection.reverting
507
659
  end
508
660
 
509
661
  class ReversibleBlockHelper < Struct.new(:reverting) # :nodoc:
@@ -525,7 +677,7 @@ module ActiveRecord
525
677
  # when the three columns 'first_name', 'last_name' and 'full_name' exist,
526
678
  # even when migrating down:
527
679
  #
528
- # class SplitNameMigration < ActiveRecord::Migration
680
+ # class SplitNameMigration < ActiveRecord::Migration[5.0]
529
681
  # def change
530
682
  # add_column :users, :first_name, :string
531
683
  # add_column :users, :last_name, :string
@@ -560,7 +712,7 @@ module ActiveRecord
560
712
  revert { run(*migration_classes, direction: dir, revert: true) }
561
713
  else
562
714
  migration_classes.each do |migration_class|
563
- migration_class.new.exec_migration(@connection, dir)
715
+ migration_class.new.exec_migration(connection, dir)
564
716
  end
565
717
  end
566
718
  end
@@ -649,10 +801,10 @@ module ActiveRecord
649
801
  end
650
802
 
651
803
  def method_missing(method, *arguments, &block)
652
- arg_list = arguments.map{ |a| a.inspect } * ', '
804
+ arg_list = arguments.map(&:inspect) * ', '
653
805
 
654
806
  say_with_time "#{method}(#{arg_list})" do
655
- unless @connection.respond_to? :revert
807
+ unless connection.respond_to? :revert
656
808
  unless arguments.empty? || [:execute, :enable_extension, :disable_extension].include?(method)
657
809
  arguments[0] = proper_table_name(arguments.first, table_name_options)
658
810
  if [:rename_table, :add_foreign_key].include?(method) ||
@@ -731,7 +883,9 @@ module ActiveRecord
731
883
  end
732
884
  end
733
885
 
734
- def table_name_options(config = ActiveRecord::Base)
886
+ # Builds a hash for use in ActiveRecord::Migration#proper_table_name using
887
+ # the Active Record object's table_name prefix and suffix
888
+ def table_name_options(config = ActiveRecord::Base) #:nodoc:
735
889
  {
736
890
  table_name_prefix: config.table_name_prefix,
737
891
  table_name_suffix: config.table_name_suffix
@@ -823,7 +977,7 @@ module ActiveRecord
823
977
  new(:up, migrations, target_version).migrate
824
978
  end
825
979
 
826
- def down(migrations_paths, target_version = nil, &block)
980
+ def down(migrations_paths, target_version = nil)
827
981
  migrations = migrations(migrations_paths)
828
982
  migrations.select! { |m| yield m } if block_given?
829
983
 
@@ -843,10 +997,12 @@ module ActiveRecord
843
997
  end
844
998
 
845
999
  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
- []
1000
+ ActiveSupport::Deprecation.silence do
1001
+ if connection.table_exists?(schema_migrations_table_name)
1002
+ SchemaMigration.all.map { |x| x.version.to_i }.sort
1003
+ else
1004
+ []
1005
+ end
850
1006
  end
851
1007
  end
852
1008
 
@@ -862,32 +1018,30 @@ module ActiveRecord
862
1018
  migrations(migrations_paths).any?
863
1019
  end
864
1020
 
865
- def last_version
866
- last_migration.version
867
- end
868
-
869
1021
  def last_migration #:nodoc:
870
1022
  migrations(migrations_paths).last || NullMigration.new
871
1023
  end
872
1024
 
873
1025
  def migrations_paths
874
1026
  @migrations_paths ||= ['db/migrate']
875
- # just to not break things if someone uses: migration_path = some_string
1027
+ # just to not break things if someone uses: migrations_path = some_string
876
1028
  Array(@migrations_paths)
877
1029
  end
878
1030
 
879
- def migrations_path
880
- migrations_paths.first
1031
+ def match_to_migration_filename?(filename) # :nodoc:
1032
+ File.basename(filename) =~ Migration::MigrationFilenameRegexp
881
1033
  end
882
1034
 
883
1035
  def parse_migration_filename(filename) # :nodoc:
884
- File.basename(filename).scan(/\A([0-9]+)_([_a-z0-9]*)\.?([_a-z0-9]*)?\.rb\z/).first
1036
+ File.basename(filename).scan(Migration::MigrationFilenameRegexp).first
885
1037
  end
886
1038
 
887
1039
  def migrations(paths)
888
1040
  paths = Array(paths)
889
1041
 
890
- migrations = migration_files(paths).map do |file|
1042
+ files = Dir[*paths.map { |p| "#{p}/**/[0-9]*_*.rb" }]
1043
+
1044
+ migrations = files.map do |file|
891
1045
  version, name, scope = parse_migration_filename(file)
892
1046
  raise IllegalMigrationNameError.new(file) unless version
893
1047
  version = version.to_i
@@ -899,30 +1053,6 @@ module ActiveRecord
899
1053
  migrations.sort_by(&:version)
900
1054
  end
901
1055
 
902
- def migrations_status(paths)
903
- paths = Array(paths)
904
-
905
- db_list = ActiveRecord::SchemaMigration.normalized_versions
906
-
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
914
-
915
- db_list.map! do |version|
916
- ["up", version, "********** NO FILE **********"]
917
- end
918
-
919
- (db_list + file_list).sort_by { |_, version, _| version }
920
- end
921
-
922
- def migration_files(paths)
923
- Dir[*paths.flat_map { |path| "#{path}/**/[0-9]*_*.rb" }]
924
- end
925
-
926
1056
  private
927
1057
 
928
1058
  def move(direction, migrations_paths, steps)
@@ -960,32 +1090,18 @@ module ActiveRecord
960
1090
  alias :current :current_migration
961
1091
 
962
1092
  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
1093
+ if use_advisory_lock?
1094
+ with_advisory_lock { run_without_lock }
1095
+ else
1096
+ run_without_lock
972
1097
  end
973
1098
  end
974
1099
 
975
1100
  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
1101
+ if use_advisory_lock?
1102
+ with_advisory_lock { migrate_without_lock }
1103
+ else
1104
+ migrate_without_lock
989
1105
  end
990
1106
  end
991
1107
 
@@ -1010,10 +1126,45 @@ module ActiveRecord
1010
1126
  end
1011
1127
 
1012
1128
  def migrated
1013
- @migrated_versions ||= Set.new(self.class.get_all_versions)
1129
+ @migrated_versions || load_migrated
1130
+ end
1131
+
1132
+ def load_migrated
1133
+ @migrated_versions = Set.new(self.class.get_all_versions)
1014
1134
  end
1015
1135
 
1016
1136
  private
1137
+
1138
+ def run_without_lock
1139
+ migration = migrations.detect { |m| m.version == @target_version }
1140
+ raise UnknownMigrationVersionError.new(@target_version) if migration.nil?
1141
+ unless (up? && migrated.include?(migration.version.to_i)) || (down? && !migrated.include?(migration.version.to_i))
1142
+ begin
1143
+ execute_migration_in_transaction(migration, @direction)
1144
+ rescue => e
1145
+ canceled_msg = use_transaction?(migration) ? ", this migration was canceled" : ""
1146
+ raise StandardError, "An error has occurred#{canceled_msg}:\n\n#{e}", e.backtrace
1147
+ end
1148
+ end
1149
+ end
1150
+
1151
+ def migrate_without_lock
1152
+ if !target && @target_version && @target_version > 0
1153
+ raise UnknownMigrationVersionError.new(@target_version)
1154
+ end
1155
+
1156
+ runnable.each do |migration|
1157
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1158
+
1159
+ begin
1160
+ execute_migration_in_transaction(migration, @direction)
1161
+ rescue => e
1162
+ canceled_msg = use_transaction?(migration) ? "this and " : ""
1163
+ raise StandardError, "An error has occurred, #{canceled_msg}all later migrations canceled:\n\n#{e}", e.backtrace
1164
+ end
1165
+ end
1166
+ end
1167
+
1017
1168
  def ran?(migration)
1018
1169
  migrated.include?(migration.version.to_i)
1019
1170
  end
@@ -1075,5 +1226,25 @@ module ActiveRecord
1075
1226
  def use_transaction?(migration)
1076
1227
  !migration.disable_ddl_transaction && Base.connection.supports_ddl_transactions?
1077
1228
  end
1229
+
1230
+ def use_advisory_lock?
1231
+ Base.connection.supports_advisory_locks?
1232
+ end
1233
+
1234
+ def with_advisory_lock
1235
+ lock_id = generate_migrator_advisory_lock_id
1236
+ got_lock = Base.connection.get_advisory_lock(lock_id)
1237
+ raise ConcurrentMigrationError unless got_lock
1238
+ load_migrated # reload schema_migrations to be sure it wasn't changed by another process before we got the lock
1239
+ yield
1240
+ ensure
1241
+ Base.connection.release_advisory_lock(lock_id) if got_lock
1242
+ end
1243
+
1244
+ MIGRATOR_SALT = 2053462845
1245
+ def generate_migrator_advisory_lock_id
1246
+ db_name_hash = Zlib.crc32(Base.connection.current_database)
1247
+ MIGRATOR_SALT * db_name_hash
1248
+ end
1078
1249
  end
1079
1250
  end