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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +123 -15
- data/MIT-LICENSE +2 -2
- data/README.rdoc +1 -1
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +1 -1
- data/lib/active_record/associations.rb +3 -0
- data/lib/active_record/associations/builder/belongs_to.rb +1 -1
- data/lib/active_record/associations/builder/has_one.rb +1 -1
- data/lib/active_record/associations/builder/singular_association.rb +1 -1
- data/lib/active_record/associations/has_many_through_association.rb +5 -0
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -2
- data/lib/active_record/associations/preloader/through_association.rb +7 -2
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +11 -7
- data/lib/active_record/autosave_association.rb +18 -3
- data/lib/active_record/base.rb +0 -3
- data/lib/active_record/collection_cache_key.rb +12 -3
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +21 -34
- data/lib/active_record/connection_adapters/abstract/quoting.rb +8 -4
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +7 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +36 -20
- data/lib/active_record/connection_adapters/abstract/transaction.rb +8 -2
- data/lib/active_record/connection_adapters/abstract_adapter.rb +8 -15
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +57 -198
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/column.rb +50 -0
- data/lib/active_record/connection_adapters/mysql/explain_pretty_printer.rb +70 -0
- data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +24 -0
- data/lib/active_record/connection_adapters/mysql/type_metadata.rb +32 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +15 -34
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +7 -69
- data/lib/active_record/connection_adapters/postgresql/explain_pretty_printer.rb +42 -0
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +4 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +0 -2
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +8 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +5 -4
- data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +3 -7
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +15 -23
- data/lib/active_record/connection_adapters/sqlite3/explain_pretty_printer.rb +19 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +2 -31
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +1 -1
- data/lib/active_record/counter_cache.rb +4 -4
- data/lib/active_record/enum.rb +8 -5
- data/lib/active_record/errors.rb +6 -1
- data/lib/active_record/gem_version.rb +1 -1
- data/lib/active_record/inheritance.rb +6 -1
- data/lib/active_record/internal_metadata.rb +56 -0
- data/lib/active_record/migration.rb +85 -20
- data/lib/active_record/migration/compatibility.rb +28 -2
- data/lib/active_record/model_schema.rb +25 -1
- data/lib/active_record/persistence.rb +11 -10
- data/lib/active_record/railtie.rb +6 -3
- data/lib/active_record/railties/databases.rake +20 -6
- data/lib/active_record/reflection.rb +39 -31
- data/lib/active_record/relation.rb +4 -4
- data/lib/active_record/relation/batches.rb +26 -41
- data/lib/active_record/relation/batches/batch_enumerator.rb +6 -6
- data/lib/active_record/relation/finder_methods.rb +35 -13
- data/lib/active_record/relation/from_clause.rb +1 -1
- data/lib/active_record/relation/merger.rb +3 -0
- data/lib/active_record/relation/predicate_builder.rb +19 -1
- data/lib/active_record/relation/predicate_builder/range_handler.rb +17 -1
- data/lib/active_record/relation/query_methods.rb +37 -19
- data/lib/active_record/relation/record_fetch_warning.rb +4 -6
- data/lib/active_record/relation/where_clause.rb +1 -1
- data/lib/active_record/relation/where_clause_factory.rb +1 -0
- data/lib/active_record/sanitization.rb +1 -1
- data/lib/active_record/schema.rb +3 -0
- data/lib/active_record/schema_dumper.rb +1 -1
- data/lib/active_record/schema_migration.rb +5 -14
- data/lib/active_record/scoping.rb +17 -11
- data/lib/active_record/scoping/default.rb +2 -2
- data/lib/active_record/tasks/database_tasks.rb +18 -0
- data/lib/active_record/timestamp.rb +5 -1
- data/lib/active_record/transactions.rb +3 -3
- data/lib/active_record/validations/uniqueness.rb +6 -3
- data/lib/rails/generators/active_record/migration/templates/migration.rb +4 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +7 -1
- 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
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
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
|
45
|
-
|
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
|
-
|
394
|
+
# Returns the version of the connected PostgreSQL server.
|
395
|
+
def postgresql_version
|
396
|
+
@connection.server_version
|
397
|
+
end
|
394
398
|
|
395
|
-
|
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]?'(.*)'
|
516
|
-
|
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
|
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
|
data/lib/active_record/core.rb
CHANGED
@@ -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
|
101
|
-
# DiscussionBoard.increment_counter(:
|
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
|
119
|
-
# DiscussionBoard.decrement_counter(:
|
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
|
data/lib/active_record/enum.rb
CHANGED
@@ -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
|
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
|
-
|
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, -> {
|
193
|
+
klass.scope value_method_name, -> { where(name => value) }
|
191
194
|
end
|
192
195
|
end
|
193
196
|
defined_enums[name.to_s] = enum_values
|
data/lib/active_record/errors.rb
CHANGED
@@ -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
|
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
|
@@ -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)
|
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
|
-
|
1142
|
-
|
1143
|
-
|
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
|
1184
|
+
if invalid_target?
|
1153
1185
|
raise UnknownMigrationVersionError.new(@target_version)
|
1154
1186
|
end
|
1155
1187
|
|
1156
1188
|
runnable.each do |migration|
|
1157
|
-
|
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!(:
|
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
|