activerecord 5.0.0.beta1.1 → 5.0.0.beta2

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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +123 -15
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +1 -1
  5. data/lib/active_record.rb +2 -1
  6. data/lib/active_record/aggregations.rb +1 -1
  7. data/lib/active_record/associations.rb +3 -0
  8. data/lib/active_record/associations/builder/belongs_to.rb +1 -1
  9. data/lib/active_record/associations/builder/has_one.rb +1 -1
  10. data/lib/active_record/associations/builder/singular_association.rb +1 -1
  11. data/lib/active_record/associations/has_many_through_association.rb +5 -0
  12. data/lib/active_record/associations/join_dependency/join_association.rb +1 -2
  13. data/lib/active_record/associations/preloader/through_association.rb +7 -2
  14. data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -7
  15. data/lib/active_record/autosave_association.rb +18 -3
  16. data/lib/active_record/base.rb +0 -3
  17. data/lib/active_record/collection_cache_key.rb +12 -3
  18. data/lib/active_record/connection_adapters/abstract/database_statements.rb +21 -34
  19. data/lib/active_record/connection_adapters/abstract/quoting.rb +8 -4
  20. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  21. data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +7 -1
  22. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +36 -20
  23. data/lib/active_record/connection_adapters/abstract/transaction.rb +8 -2
  24. data/lib/active_record/connection_adapters/abstract_adapter.rb +8 -15
  25. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +57 -198
  26. data/lib/active_record/connection_adapters/column.rb +1 -1
  27. data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
  28. data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
  29. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +24 -0
  30. data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
  31. data/lib/active_record/connection_adapters/mysql2_adapter.rb +15 -34
  32. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +7 -69
  33. data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
  34. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +4 -0
  35. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
  36. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -1
  37. data/lib/active_record/connection_adapters/postgresql/quoting.rb +5 -4
  38. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -7
  39. data/lib/active_record/connection_adapters/postgresql_adapter.rb +15 -23
  40. data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
  41. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -31
  42. data/lib/active_record/connection_handling.rb +1 -1
  43. data/lib/active_record/core.rb +1 -1
  44. data/lib/active_record/counter_cache.rb +4 -4
  45. data/lib/active_record/enum.rb +8 -5
  46. data/lib/active_record/errors.rb +6 -1
  47. data/lib/active_record/gem_version.rb +1 -1
  48. data/lib/active_record/inheritance.rb +6 -1
  49. data/lib/active_record/internal_metadata.rb +56 -0
  50. data/lib/active_record/migration.rb +85 -20
  51. data/lib/active_record/migration/compatibility.rb +28 -2
  52. data/lib/active_record/model_schema.rb +25 -1
  53. data/lib/active_record/persistence.rb +11 -10
  54. data/lib/active_record/railtie.rb +6 -3
  55. data/lib/active_record/railties/databases.rake +20 -6
  56. data/lib/active_record/reflection.rb +39 -31
  57. data/lib/active_record/relation.rb +4 -4
  58. data/lib/active_record/relation/batches.rb +26 -41
  59. data/lib/active_record/relation/batches/batch_enumerator.rb +6 -6
  60. data/lib/active_record/relation/finder_methods.rb +35 -13
  61. data/lib/active_record/relation/from_clause.rb +1 -1
  62. data/lib/active_record/relation/merger.rb +3 -0
  63. data/lib/active_record/relation/predicate_builder.rb +19 -1
  64. data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -1
  65. data/lib/active_record/relation/query_methods.rb +37 -19
  66. data/lib/active_record/relation/record_fetch_warning.rb +4 -6
  67. data/lib/active_record/relation/where_clause.rb +1 -1
  68. data/lib/active_record/relation/where_clause_factory.rb +1 -0
  69. data/lib/active_record/sanitization.rb +1 -1
  70. data/lib/active_record/schema.rb +3 -0
  71. data/lib/active_record/schema_dumper.rb +1 -1
  72. data/lib/active_record/schema_migration.rb +5 -14
  73. data/lib/active_record/scoping.rb +17 -11
  74. data/lib/active_record/scoping/default.rb +2 -2
  75. data/lib/active_record/tasks/database_tasks.rb +18 -0
  76. data/lib/active_record/timestamp.rb +5 -1
  77. data/lib/active_record/transactions.rb +3 -3
  78. data/lib/active_record/validations/uniqueness.rb +6 -3
  79. data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -0
  80. data/lib/rails/generators/active_record/model/model_generator.rb +7 -1
  81. metadata +14 -7
@@ -6,6 +6,7 @@ module ActiveRecord
6
6
  module OID # :nodoc:
7
7
  class Range < Type::Value # :nodoc:
8
8
  attr_reader :subtype, :type
9
+ delegate :user_input_in_time_zone, to: :subtype
9
10
 
10
11
  def initialize(subtype, type = :range)
11
12
  @subtype = subtype
@@ -18,7 +19,7 @@ module ActiveRecord
18
19
 
19
20
  def cast_value(value)
20
21
  return if value == 'empty'
21
- return value if value.is_a?(::Range)
22
+ return value unless value.is_a?(::String)
22
23
 
23
24
  extracted = extract_bounds(value)
24
25
  from = type_cast_single extracted[:from]
@@ -46,6 +47,12 @@ module ActiveRecord
46
47
  other.type == type
47
48
  end
48
49
 
50
+ def map(value) # :nodoc:
51
+ new_begin = yield(value.begin)
52
+ new_end = yield(value.end)
53
+ ::Range.new(new_begin, new_end, value.exclude_end?)
54
+ end
55
+
49
56
  private
50
57
 
51
58
  def type_cast_single(value)
@@ -55,10 +55,11 @@ module ActiveRecord
55
55
  end
56
56
  end
57
57
 
58
- # Does not quote function default values for UUID columns
59
- def quote_default_expression(value, column) #:nodoc:
60
- if column.type == :uuid && value =~ /\(\)/
61
- value
58
+ def quote_default_expression(value, column) # :nodoc:
59
+ if value.is_a?(Proc)
60
+ value.call
61
+ elsif column.type == :uuid && value =~ /\(\)/
62
+ value # Does not quote function default values for UUID columns
62
63
  elsif column.respond_to?(:array?)
63
64
  value = type_cast_from_column(column, value)
64
65
  quote(value)
@@ -9,7 +9,7 @@ module ActiveRecord
9
9
  spec[:id] = ':bigserial'
10
10
  elsif column.type == :uuid
11
11
  spec[:id] = ':uuid'
12
- spec[:default] = column.default_function.inspect
12
+ spec[:default] = schema_default(column) || 'nil'
13
13
  else
14
14
  spec[:id] = column.type.inspect
15
15
  spec.merge!(prepare_column_options(column).delete_if { |key, _| [:name, :type, :null].include?(key) })
@@ -41,12 +41,8 @@ module ActiveRecord
41
41
  end
42
42
  end
43
43
 
44
- def schema_default(column)
45
- if column.default_function
46
- column.default_function.inspect unless column.serial?
47
- else
48
- super
49
- end
44
+ def schema_expression(column)
45
+ super unless column.serial?
50
46
  end
51
47
  end
52
48
  end
@@ -5,6 +5,7 @@ require 'pg'
5
5
  require "active_record/connection_adapters/abstract_adapter"
6
6
  require "active_record/connection_adapters/postgresql/column"
7
7
  require "active_record/connection_adapters/postgresql/database_statements"
8
+ require "active_record/connection_adapters/postgresql/explain_pretty_printer"
8
9
  require "active_record/connection_adapters/postgresql/oid"
9
10
  require "active_record/connection_adapters/postgresql/quoting"
10
11
  require "active_record/connection_adapters/postgresql/referential_integrity"
@@ -390,12 +391,12 @@ module ActiveRecord
390
391
  "average" => "avg",
391
392
  }
392
393
 
393
- protected
394
+ # Returns the version of the connected PostgreSQL server.
395
+ def postgresql_version
396
+ @connection.server_version
397
+ end
394
398
 
395
- # Returns the version of the connected PostgreSQL server.
396
- def postgresql_version
397
- @connection.server_version
398
- end
399
+ protected
399
400
 
400
401
  # See http://www.postgresql.org/docs/current/static/errcodes-appendix.html
401
402
  FOREIGN_KEY_VIOLATION = "23503"
@@ -512,8 +513,13 @@ module ActiveRecord
512
513
  def extract_value_from_default(default) # :nodoc:
513
514
  case default
514
515
  # Quoted types
515
- when /\A[\(B]?'(.*)'::/m
516
- $1.gsub("''".freeze, "'".freeze)
516
+ when /\A[\(B]?'(.*)'.*::"?([\w. ]+)"?(?:\[\])?\z/m
517
+ # The default 'now'::date is CURRENT_DATE
518
+ if $1 == "now".freeze && $2 == "date".freeze
519
+ nil
520
+ else
521
+ $1.gsub("''".freeze, "'".freeze)
522
+ end
517
523
  # Boolean types
518
524
  when 'true'.freeze, 'false'.freeze
519
525
  default
@@ -535,7 +541,7 @@ module ActiveRecord
535
541
  end
536
542
 
537
543
  def has_default_function?(default_value, default) # :nodoc:
538
- !default_value && (%r{\w+\(.*\)} === default)
544
+ !default_value && (%r{\w+\(.*\)|\(.*\)::\w+} === default)
539
545
  end
540
546
 
541
547
  def load_additional_types(type_map, oids = nil) # :nodoc:
@@ -640,12 +646,6 @@ module ActiveRecord
640
646
  # connected server's characteristics.
641
647
  def connect
642
648
  @connection = PGconn.connect(@connection_parameters)
643
-
644
- # Money type has a fixed precision of 10 in PostgreSQL 8.2 and below, and as of
645
- # PostgreSQL 8.3 it has a fixed precision of 19. PostgreSQLColumn.extract_precision
646
- # should know about this but can't detect it there, so deal with it here.
647
- OID::Money.precision = (postgresql_version >= 80300) ? 19 : 10
648
-
649
649
  configure_connection
650
650
  rescue ::PG::Error => error
651
651
  if error.message.include?("does not exist")
@@ -690,15 +690,7 @@ module ActiveRecord
690
690
  end
691
691
 
692
692
  # Returns the current ID of a table's sequence.
693
- def last_insert_id(sequence_name) #:nodoc:
694
- Integer(last_insert_id_value(sequence_name))
695
- end
696
-
697
- def last_insert_id_value(sequence_name)
698
- last_insert_id_result(sequence_name).rows.first.first
699
- end
700
-
701
- def last_insert_id_result(sequence_name) #:nodoc:
693
+ def last_insert_id_result(sequence_name) # :nodoc:
702
694
  exec_query("SELECT currval('#{sequence_name}')", 'SQL')
703
695
  end
704
696
 
@@ -0,0 +1,19 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLite3
4
+ class ExplainPrettyPrinter # :nodoc:
5
+ # Pretty prints the result of an EXPLAIN QUERY PLAN in a way that resembles
6
+ # the output of the SQLite shell:
7
+ #
8
+ # 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
9
+ # 0|1|1|SCAN TABLE posts (~100000 rows)
10
+ #
11
+ def pp(result)
12
+ result.rows.map do |row|
13
+ row.join('|')
14
+ end.join("\n") + "\n"
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,6 @@
1
1
  require 'active_record/connection_adapters/abstract_adapter'
2
2
  require 'active_record/connection_adapters/statement_pool'
3
+ require 'active_record/connection_adapters/sqlite3/explain_pretty_printer'
3
4
  require 'active_record/connection_adapters/sqlite3/schema_creation'
4
5
 
5
6
  gem 'sqlite3', '~> 1.3.6'
@@ -218,21 +219,7 @@ module ActiveRecord
218
219
 
219
220
  def explain(arel, binds = [])
220
221
  sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
221
- ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
222
- end
223
-
224
- class ExplainPrettyPrinter
225
- # Pretty prints the result of an EXPLAIN QUERY PLAN in a way that resembles
226
- # the output of the SQLite shell:
227
- #
228
- # 0|0|0|SEARCH TABLE users USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
229
- # 0|1|1|SCAN TABLE posts (~100000 rows)
230
- #
231
- def pp(result) # :nodoc:
232
- result.rows.map do |row|
233
- row.join('|')
234
- end.join("\n") + "\n"
235
- end
222
+ SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, 'EXPLAIN', []))
236
223
  end
237
224
 
238
225
  def exec_query(sql, name = nil, binds = [], prepare: false)
@@ -280,22 +267,6 @@ module ActiveRecord
280
267
  log(sql, name) { @connection.execute(sql) }
281
268
  end
282
269
 
283
- def update_sql(sql, name = nil) #:nodoc:
284
- super
285
- @connection.changes
286
- end
287
-
288
- def delete_sql(sql, name = nil) #:nodoc:
289
- sql += " WHERE 1=1" unless sql =~ /WHERE/i
290
- super sql, name
291
- end
292
-
293
- def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
294
- super
295
- id_value || @connection.last_insert_row_id
296
- end
297
- alias :create :insert_sql
298
-
299
270
  def select_rows(sql, name = nil, binds = [])
300
271
  exec_query(sql, name, binds).rows
301
272
  end
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  # example for regular databases (MySQL, PostgreSQL, etc):
9
9
  #
10
10
  # ActiveRecord::Base.establish_connection(
11
- # adapter: "mysql",
11
+ # adapter: "mysql2",
12
12
  # host: "localhost",
13
13
  # username: "myuser",
14
14
  # password: "mypass",
@@ -275,7 +275,7 @@ module ActiveRecord
275
275
  def relation # :nodoc:
276
276
  relation = Relation.create(self, arel_table, predicate_builder)
277
277
 
278
- if finder_needs_type_condition?
278
+ if finder_needs_type_condition? && !ignore_default_scope?
279
279
  relation.where(type_condition).create_with(inheritance_column.to_sym => sti_name)
280
280
  else
281
281
  relation
@@ -97,8 +97,8 @@ module ActiveRecord
97
97
  #
98
98
  # ==== Examples
99
99
  #
100
- # # Increment the post_count column for the record with an id of 5
101
- # DiscussionBoard.increment_counter(:post_count, 5)
100
+ # # Increment the posts_count column for the record with an id of 5
101
+ # DiscussionBoard.increment_counter(:posts_count, 5)
102
102
  def increment_counter(counter_name, id)
103
103
  update_counters(id, counter_name => 1)
104
104
  end
@@ -115,8 +115,8 @@ module ActiveRecord
115
115
  #
116
116
  # ==== Examples
117
117
  #
118
- # # Decrement the post_count column for the record with an id of 5
119
- # DiscussionBoard.decrement_counter(:post_count, 5)
118
+ # # Decrement the posts_count column for the record with an id of 5
119
+ # DiscussionBoard.decrement_counter(:posts_count, 5)
120
120
  def decrement_counter(counter_name, id)
121
121
  update_counters(id, counter_name => -1)
122
122
  end
@@ -105,9 +105,10 @@ module ActiveRecord
105
105
  end
106
106
 
107
107
  class EnumType < Type::Value # :nodoc:
108
- def initialize(name, mapping)
108
+ def initialize(name, mapping, subtype)
109
109
  @name = name
110
110
  @mapping = mapping
111
+ @subtype = subtype
111
112
  end
112
113
 
113
114
  def cast(value)
@@ -124,7 +125,7 @@ module ActiveRecord
124
125
 
125
126
  def deserialize(value)
126
127
  return if value.nil?
127
- mapping.key(value.to_i)
128
+ mapping.key(subtype.deserialize(value))
128
129
  end
129
130
 
130
131
  def serialize(value)
@@ -139,7 +140,7 @@ module ActiveRecord
139
140
 
140
141
  protected
141
142
 
142
- attr_reader :name, :mapping
143
+ attr_reader :name, :mapping, :subtype
143
144
  end
144
145
 
145
146
  def enum(definitions)
@@ -158,7 +159,9 @@ module ActiveRecord
158
159
  detect_enum_conflict!(name, name)
159
160
  detect_enum_conflict!(name, "#{name}=")
160
161
 
161
- attribute name, EnumType.new(name, enum_values)
162
+ decorate_attribute_type(name, :enum) do |subtype|
163
+ EnumType.new(name, enum_values, subtype)
164
+ end
162
165
 
163
166
  _enum_methods_module.module_eval do
164
167
  pairs = values.respond_to?(:each_pair) ? values.each_pair : values.each_with_index
@@ -187,7 +190,7 @@ module ActiveRecord
187
190
 
188
191
  # scope :active, -> { where status: 0 }
189
192
  klass.send(:detect_enum_conflict!, name, value_method_name, true)
190
- klass.scope value_method_name, -> { klass.where name => value }
193
+ klass.scope value_method_name, -> { where(name => value) }
191
194
  end
192
195
  end
193
196
  defined_enums[name.to_s] = enum_values
@@ -272,7 +272,12 @@ module ActiveRecord
272
272
  # * You are joining an existing open transaction
273
273
  # * You are creating a nested (savepoint) transaction
274
274
  #
275
- # The mysql, mysql2 and postgresql adapters support setting the transaction isolation level.
275
+ # The mysql2 and postgresql adapters support setting the transaction isolation level.
276
276
  class TransactionIsolationError < ActiveRecordError
277
277
  end
278
+
279
+ # IrreversibleOrderError is raised when a relation's order is too complex for
280
+ # +reverse_order+ to automatically reverse.
281
+ class IrreversibleOrderError < ActiveRecordError
282
+ end
278
283
  end
@@ -8,7 +8,7 @@ module ActiveRecord
8
8
  MAJOR = 5
9
9
  MINOR = 0
10
10
  TINY = 0
11
- PRE = "beta1.1"
11
+ PRE = "beta2"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -52,7 +52,11 @@ module ActiveRecord
52
52
 
53
53
  attrs = args.first
54
54
  if has_attribute?(inheritance_column)
55
- subclass = subclass_from_attributes(attrs) || subclass_from_attributes(column_defaults)
55
+ subclass = subclass_from_attributes(attrs)
56
+
57
+ if subclass.nil? && base_class == self
58
+ subclass = subclass_from_attributes(column_defaults)
59
+ end
56
60
  end
57
61
 
58
62
  if subclass && subclass != self
@@ -167,6 +171,7 @@ module ActiveRecord
167
171
  end
168
172
 
169
173
  def find_sti_class(type_name)
174
+ type_name = base_class.type_for_attribute(inheritance_column).cast(type_name)
170
175
  subclass = begin
171
176
  if store_full_sti_class
172
177
  ActiveSupport::Dependencies.constantize(type_name)
@@ -0,0 +1,56 @@
1
+ require 'active_record/scoping/default'
2
+ require 'active_record/scoping/named'
3
+
4
+ module ActiveRecord
5
+ # This class is used to create a table that keeps track of values and keys such
6
+ # as which environment migrations were run in.
7
+ class InternalMetadata < ActiveRecord::Base # :nodoc:
8
+ class << self
9
+ def primary_key
10
+ "key"
11
+ end
12
+
13
+ def table_name
14
+ "#{table_name_prefix}#{ActiveRecord::Base.internal_metadata_table_name}#{table_name_suffix}"
15
+ end
16
+
17
+ def original_table_name
18
+ "#{table_name_prefix}active_record_internal_metadatas#{table_name_suffix}"
19
+ end
20
+
21
+ def []=(key, value)
22
+ first_or_initialize(key: key).update_attributes!(value: value)
23
+ end
24
+
25
+ def [](key)
26
+ where(key: key).pluck(:value).first
27
+ end
28
+
29
+ def table_exists?
30
+ ActiveSupport::Deprecation.silence { connection.table_exists?(table_name) }
31
+ end
32
+
33
+ def original_table_exists?
34
+ # This method will be removed in Rails 5.1
35
+ # Since it is only necessary when `active_record_internal_metadatas` could exist
36
+ ActiveSupport::Deprecation.silence { connection.table_exists?(original_table_name) }
37
+ end
38
+
39
+ # Creates an internal metadata table with columns +key+ and +value+
40
+ def create_table
41
+ if original_table_exists?
42
+ connection.rename_table(original_table_name, table_name)
43
+ end
44
+ unless table_exists?
45
+ key_options = connection.internal_string_options_for_primary_key
46
+
47
+ connection.create_table(table_name, id: false) do |t|
48
+ t.string :key, key_options
49
+ t.string :value
50
+ t.timestamps
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -126,9 +126,9 @@ module ActiveRecord
126
126
  class PendingMigrationError < MigrationError#:nodoc:
127
127
  def initialize(message = nil)
128
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}.")
129
+ super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate RAILS_ENV=#{::Rails.env}")
130
130
  elsif !message
131
- super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate.")
131
+ super("Migrations are pending. To resolve this issue, run:\n\n\tbin/rails db:migrate")
132
132
  else
133
133
  super
134
134
  end
@@ -143,6 +143,40 @@ module ActiveRecord
143
143
  end
144
144
  end
145
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}")
174
+ else
175
+ super(msg)
176
+ end
177
+ end
178
+ end
179
+
146
180
  # = Active Record Migrations
147
181
  #
148
182
  # Migrations can manage the evolution of a schema used by several physical
@@ -1078,6 +1112,7 @@ module ActiveRecord
1078
1112
  validate(@migrations)
1079
1113
 
1080
1114
  Base.connection.initialize_schema_migrations_table
1115
+ Base.connection.initialize_internal_metadata_table
1081
1116
  end
1082
1117
 
1083
1118
  def current_version
@@ -1135,45 +1170,58 @@ module ActiveRecord
1135
1170
 
1136
1171
  private
1137
1172
 
1173
+ # Used for running a specific migration.
1138
1174
  def run_without_lock
1139
1175
  migration = migrations.detect { |m| m.version == @target_version }
1140
1176
  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
1177
+ execute_migration_in_transaction(migration, @direction)
1178
+
1179
+ record_environment
1149
1180
  end
1150
1181
 
1182
+ # Used for running multiple migrations up to or down to a certain value.
1151
1183
  def migrate_without_lock
1152
- if !target && @target_version && @target_version > 0
1184
+ if invalid_target?
1153
1185
  raise UnknownMigrationVersionError.new(@target_version)
1154
1186
  end
1155
1187
 
1156
1188
  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
1189
+ execute_migration_in_transaction(migration, @direction)
1165
1190
  end
1191
+
1192
+ record_environment
1193
+ end
1194
+
1195
+ # Stores the current environment in the database.
1196
+ def record_environment
1197
+ return if down?
1198
+ ActiveRecord::InternalMetadata[:environment] = ActiveRecord::Migrator.current_environment
1166
1199
  end
1167
1200
 
1168
1201
  def ran?(migration)
1169
1202
  migrated.include?(migration.version.to_i)
1170
1203
  end
1171
1204
 
1205
+ # Return true if a valid version is not provided.
1206
+ def invalid_target?
1207
+ !target && @target_version && @target_version > 0
1208
+ end
1209
+
1172
1210
  def execute_migration_in_transaction(migration, direction)
1211
+ return if down? && !migrated.include?(migration.version.to_i)
1212
+ return if up? && migrated.include?(migration.version.to_i)
1213
+
1214
+ Base.logger.info "Migrating to #{migration.name} (#{migration.version})" if Base.logger
1215
+
1173
1216
  ddl_transaction(migration) do
1174
1217
  migration.migrate(direction)
1175
1218
  record_version_state_after_migrating(migration.version)
1176
1219
  end
1220
+ rescue => e
1221
+ msg = "An error has occurred, "
1222
+ msg << "this and " if use_transaction?(migration)
1223
+ msg << "all later migrations canceled:\n\n#{e}"
1224
+ raise StandardError, msg, e.backtrace
1177
1225
  end
1178
1226
 
1179
1227
  def target
@@ -1202,10 +1250,27 @@ module ActiveRecord
1202
1250
  ActiveRecord::SchemaMigration.where(:version => version.to_s).delete_all
1203
1251
  else
1204
1252
  migrated << version
1205
- ActiveRecord::SchemaMigration.create!(:version => version.to_s)
1253
+ ActiveRecord::SchemaMigration.create!(version: version.to_s)
1206
1254
  end
1207
1255
  end
1208
1256
 
1257
+ def self.last_stored_environment
1258
+ return nil if current_version == 0
1259
+ raise NoEnvironmentInSchemaError unless ActiveRecord::InternalMetadata.table_exists?
1260
+
1261
+ environment = ActiveRecord::InternalMetadata[:environment]
1262
+ raise NoEnvironmentInSchemaError unless environment
1263
+ environment
1264
+ end
1265
+
1266
+ def self.current_environment
1267
+ ActiveRecord::ConnectionHandling::DEFAULT_ENV.call
1268
+ end
1269
+
1270
+ def self.protected_environment?
1271
+ ActiveRecord::Base.protected_environments.include?(last_stored_environment) if last_stored_environment
1272
+ end
1273
+
1209
1274
  def up?
1210
1275
  @direction == :up
1211
1276
  end