activerecord 5.1.4 → 5.1.5.rc1
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 +5 -5
- data/CHANGELOG.md +151 -0
- data/lib/active_record/associations/belongs_to_association.rb +2 -2
- data/lib/active_record/associations/builder/belongs_to.rb +7 -3
- data/lib/active_record/associations/has_many_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +3 -3
- data/lib/active_record/associations/join_dependency/join_association.rb +1 -9
- data/lib/active_record/associations/preloader/association.rb +11 -34
- data/lib/active_record/associations/preloader/through_association.rb +10 -3
- data/lib/active_record/attribute_methods/dirty.rb +3 -2
- data/lib/active_record/collection_cache_key.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
- data/lib/active_record/connection_adapters/abstract_adapter.rb +2 -1
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +5 -4
- data/lib/active_record/connection_adapters/column.rb +1 -1
- data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -0
- data/lib/active_record/connection_adapters/postgresql/column.rb +28 -1
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -1
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +5 -3
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +11 -4
- data/lib/active_record/gem_version.rb +2 -2
- data/lib/active_record/locking/pessimistic.rb +1 -1
- data/lib/active_record/log_subscriber.rb +3 -4
- data/lib/active_record/migration/compatibility.rb +34 -20
- data/lib/active_record/model_schema.rb +33 -33
- data/lib/active_record/persistence.rb +1 -5
- data/lib/active_record/query_cache.rb +6 -6
- data/lib/active_record/railties/databases.rake +2 -2
- data/lib/active_record/reflection.rb +24 -10
- data/lib/active_record/relation.rb +14 -2
- data/lib/active_record/relation/calculations.rb +16 -11
- data/lib/active_record/relation/finder_methods.rb +1 -11
- data/lib/active_record/relation/query_methods.rb +19 -14
- data/lib/active_record/tasks/database_tasks.rb +11 -10
- metadata +12 -10
@@ -13,7 +13,7 @@ module ActiveRecord
|
|
13
13
|
# +default+ is the type-casted default value, such as +new+ in <tt>sales_stage varchar(20) default 'new'</tt>.
|
14
14
|
# +sql_type_metadata+ is various information about the type of the column
|
15
15
|
# +null+ determines if this column allows +NULL+ values.
|
16
|
-
def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil)
|
16
|
+
def initialize(name, default, sql_type_metadata = nil, null = true, table_name = nil, default_function = nil, collation = nil, comment: nil, **)
|
17
17
|
@name = name.freeze
|
18
18
|
@table_name = table_name
|
19
19
|
@sql_type_metadata = sql_type_metadata
|
@@ -5,6 +5,7 @@ module ActiveRecord
|
|
5
5
|
def prepare_column_options(column)
|
6
6
|
spec = super
|
7
7
|
spec[:unsigned] = "true" if column.unsigned?
|
8
|
+
spec[:auto_increment] = "true" if column.auto_increment?
|
8
9
|
|
9
10
|
if supports_virtual_columns? && column.virtual?
|
10
11
|
spec[:as] = extract_expression_for_virtual_column(column)
|
@@ -15,6 +16,12 @@ module ActiveRecord
|
|
15
16
|
spec
|
16
17
|
end
|
17
18
|
|
19
|
+
def column_spec_for_primary_key(column)
|
20
|
+
spec = super
|
21
|
+
spec.delete(:auto_increment) if column.type == :integer && column.auto_increment?
|
22
|
+
spec
|
23
|
+
end
|
24
|
+
|
18
25
|
def migration_keys
|
19
26
|
super + [:unsigned]
|
20
27
|
end
|
@@ -5,11 +5,38 @@ module ActiveRecord
|
|
5
5
|
delegate :array, :oid, :fmod, to: :sql_type_metadata
|
6
6
|
alias :array? :array
|
7
7
|
|
8
|
+
def initialize(*, max_identifier_length: 63, **)
|
9
|
+
super
|
10
|
+
@max_identifier_length = max_identifier_length
|
11
|
+
end
|
12
|
+
|
8
13
|
def serial?
|
9
14
|
return unless default_function
|
10
15
|
|
11
|
-
%r{\Anextval\('"
|
16
|
+
if %r{\Anextval\('"?(?<sequence_name>.+_(?<suffix>seq\d*))"?'::regclass\)\z} =~ default_function
|
17
|
+
sequence_name_from_parts(table_name, name, suffix) == sequence_name
|
18
|
+
end
|
12
19
|
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
attr_reader :max_identifier_length
|
23
|
+
|
24
|
+
private
|
25
|
+
def sequence_name_from_parts(table_name, column_name, suffix)
|
26
|
+
over_length = [table_name, column_name, suffix].map(&:length).sum + 2 - max_identifier_length
|
27
|
+
|
28
|
+
if over_length > 0
|
29
|
+
column_name_length = [(max_identifier_length - suffix.length - 2) / 2, column_name.length].min
|
30
|
+
over_length -= column_name.length - column_name_length
|
31
|
+
column_name = column_name[0, column_name_length - [over_length, 0].min]
|
32
|
+
end
|
33
|
+
|
34
|
+
if over_length > 0
|
35
|
+
table_name = table_name[0, table_name.length - over_length]
|
36
|
+
end
|
37
|
+
|
38
|
+
"#{table_name}_#{column_name}_#{suffix}"
|
39
|
+
end
|
13
40
|
end
|
14
41
|
end
|
15
42
|
end
|
@@ -62,7 +62,7 @@ module ActiveRecord
|
|
62
62
|
def quote_default_expression(value, column) # :nodoc:
|
63
63
|
if value.is_a?(Proc)
|
64
64
|
value.call
|
65
|
-
elsif column.type == :uuid && /\(\)/.match?(value)
|
65
|
+
elsif column.type == :uuid && value.is_a?(String) && /\(\)/.match?(value)
|
66
66
|
value # Does not quote function default values for UUID columns
|
67
67
|
elsif column.respond_to?(:array?)
|
68
68
|
value = type_cast_from_column(column, value)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Make sure we're using pg high enough for type casts and Ruby 2.2+ compatibility
|
2
|
-
gem "pg", "
|
2
|
+
gem "pg", ">= 0.18", "< 2.0"
|
3
3
|
require "pg"
|
4
4
|
|
5
5
|
require "active_record/connection_adapters/abstract_adapter"
|
@@ -198,6 +198,7 @@ module ActiveRecord
|
|
198
198
|
|
199
199
|
def dealloc(key)
|
200
200
|
@connection.query "DEALLOCATE #{key}" if connection_active?
|
201
|
+
rescue PG::Error
|
201
202
|
end
|
202
203
|
|
203
204
|
def connection_active?
|
@@ -364,10 +365,11 @@ module ActiveRecord
|
|
364
365
|
end
|
365
366
|
|
366
367
|
# Returns the configured supported identifier length supported by PostgreSQL
|
367
|
-
def
|
368
|
+
def max_identifier_length
|
368
369
|
@max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
|
369
370
|
end
|
370
|
-
alias
|
371
|
+
alias table_alias_length max_identifier_length
|
372
|
+
alias index_name_length max_identifier_length
|
371
373
|
|
372
374
|
# Set the authorized user for this session
|
373
375
|
def session_auth=(user)
|
@@ -340,7 +340,7 @@ module ActiveRecord
|
|
340
340
|
end
|
341
341
|
|
342
342
|
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
343
|
-
if valid_alter_table_type?(type)
|
343
|
+
if valid_alter_table_type?(type) && !options[:primary_key]
|
344
344
|
super(table_name, column_name, type, options)
|
345
345
|
else
|
346
346
|
alter_table(table_name) do |definition|
|
@@ -440,18 +440,21 @@ module ActiveRecord
|
|
440
440
|
options[:id] = false
|
441
441
|
create_table(to, options) do |definition|
|
442
442
|
@definition = definition
|
443
|
-
|
443
|
+
if from_primary_key.is_a?(Array)
|
444
|
+
@definition.primary_keys from_primary_key
|
445
|
+
end
|
444
446
|
columns(from).each do |column|
|
445
447
|
column_name = options[:rename] ?
|
446
448
|
(options[:rename][column.name] ||
|
447
449
|
options[:rename][column.name.to_sym] ||
|
448
450
|
column.name) : column.name
|
449
|
-
next if column_name == from_primary_key
|
450
451
|
|
451
452
|
@definition.column(column_name, column.type,
|
452
453
|
limit: column.limit, default: column.default,
|
453
454
|
precision: column.precision, scale: column.scale,
|
454
|
-
null: column.null, collation: column.collation
|
455
|
+
null: column.null, collation: column.collation,
|
456
|
+
primary_key: column_name == from_primary_key
|
457
|
+
)
|
455
458
|
end
|
456
459
|
yield @definition if block_given?
|
457
460
|
end
|
@@ -464,6 +467,9 @@ module ActiveRecord
|
|
464
467
|
def copy_table_indexes(from, to, rename = {})
|
465
468
|
indexes(from).each do |index|
|
466
469
|
name = index.name
|
470
|
+
# indexes sqlite creates for internal use start with `sqlite_` and
|
471
|
+
# don't need to be copied
|
472
|
+
next if name.starts_with?("sqlite_")
|
467
473
|
if to == "a#{from}"
|
468
474
|
name = "t#{name}"
|
469
475
|
elsif from == "a#{to}"
|
@@ -479,6 +485,7 @@ module ActiveRecord
|
|
479
485
|
# index name can't be the same
|
480
486
|
opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
|
481
487
|
opts[:unique] = true if index.unique
|
488
|
+
opts[:where] = index.where if index.where
|
482
489
|
add_index(to, columns, opts)
|
483
490
|
end
|
484
491
|
end
|
@@ -60,7 +60,7 @@ module ActiveRecord
|
|
60
60
|
# the locked record.
|
61
61
|
def lock!(lock = true)
|
62
62
|
if persisted?
|
63
|
-
if
|
63
|
+
if has_changes_to_save?
|
64
64
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
65
65
|
Locking a record with unpersisted changes is deprecated and will raise an
|
66
66
|
exception in Rails 5.2. Use `save` to persist the changes, or `reload` to
|
@@ -29,7 +29,7 @@ module ActiveRecord
|
|
29
29
|
binds = nil
|
30
30
|
|
31
31
|
unless (payload[:binds] || []).empty?
|
32
|
-
casted_params = type_casted_binds(payload[:
|
32
|
+
casted_params = type_casted_binds(payload[:type_casted_binds])
|
33
33
|
binds = " " + payload[:binds].zip(casted_params).map { |attr, value|
|
34
34
|
render_bind(attr, value)
|
35
35
|
}.inspect
|
@@ -42,9 +42,8 @@ module ActiveRecord
|
|
42
42
|
end
|
43
43
|
|
44
44
|
private
|
45
|
-
|
46
|
-
|
47
|
-
casted_binds || ActiveRecord::Base.connection.type_casted_binds(binds)
|
45
|
+
def type_casted_binds(casted_binds)
|
46
|
+
casted_binds.respond_to?(:call) ? casted_binds.call : casted_binds
|
48
47
|
end
|
49
48
|
|
50
49
|
def render_bind(attr, value)
|
@@ -42,11 +42,8 @@ module ActiveRecord
|
|
42
42
|
end
|
43
43
|
|
44
44
|
if block_given?
|
45
|
-
super
|
46
|
-
|
47
|
-
prepend TableDefinition
|
48
|
-
end
|
49
|
-
yield t
|
45
|
+
super do |t|
|
46
|
+
yield compatible_table_definition(t)
|
50
47
|
end
|
51
48
|
else
|
52
49
|
super
|
@@ -55,11 +52,20 @@ module ActiveRecord
|
|
55
52
|
|
56
53
|
def change_table(table_name, options = {})
|
57
54
|
if block_given?
|
58
|
-
super
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
55
|
+
super do |t|
|
56
|
+
yield compatible_table_definition(t)
|
57
|
+
end
|
58
|
+
else
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_join_table(table_1, table_2, column_options: {}, **options)
|
64
|
+
column_options.reverse_merge!(type: :integer)
|
65
|
+
|
66
|
+
if block_given?
|
67
|
+
super do |t|
|
68
|
+
yield compatible_table_definition(t)
|
63
69
|
end
|
64
70
|
else
|
65
71
|
super
|
@@ -70,6 +76,14 @@ module ActiveRecord
|
|
70
76
|
super(table_name, ref_name, type: :integer, **options)
|
71
77
|
end
|
72
78
|
alias :add_belongs_to :add_reference
|
79
|
+
|
80
|
+
private
|
81
|
+
def compatible_table_definition(t)
|
82
|
+
class << t
|
83
|
+
prepend TableDefinition
|
84
|
+
end
|
85
|
+
t
|
86
|
+
end
|
73
87
|
end
|
74
88
|
|
75
89
|
class V4_2 < V5_0
|
@@ -88,11 +102,8 @@ module ActiveRecord
|
|
88
102
|
|
89
103
|
def create_table(table_name, options = {})
|
90
104
|
if block_given?
|
91
|
-
super
|
92
|
-
|
93
|
-
prepend TableDefinition
|
94
|
-
end
|
95
|
-
yield t
|
105
|
+
super do |t|
|
106
|
+
yield compatible_table_definition(t)
|
96
107
|
end
|
97
108
|
else
|
98
109
|
super
|
@@ -101,11 +112,8 @@ module ActiveRecord
|
|
101
112
|
|
102
113
|
def change_table(table_name, options = {})
|
103
114
|
if block_given?
|
104
|
-
super
|
105
|
-
|
106
|
-
prepend TableDefinition
|
107
|
-
end
|
108
|
-
yield t
|
115
|
+
super do |t|
|
116
|
+
yield compatible_table_definition(t)
|
109
117
|
end
|
110
118
|
else
|
111
119
|
super
|
@@ -141,6 +149,12 @@ module ActiveRecord
|
|
141
149
|
end
|
142
150
|
|
143
151
|
private
|
152
|
+
def compatible_table_definition(t)
|
153
|
+
class << t
|
154
|
+
prepend TableDefinition
|
155
|
+
end
|
156
|
+
super
|
157
|
+
end
|
144
158
|
|
145
159
|
def index_name_for_remove(table_name, options = {})
|
146
160
|
index_name = index_name(table_name, options)
|
@@ -84,19 +84,6 @@ module ActiveRecord
|
|
84
84
|
#
|
85
85
|
# Sets the name of the internal metadata table.
|
86
86
|
|
87
|
-
##
|
88
|
-
# :singleton-method: protected_environments
|
89
|
-
# :call-seq: protected_environments
|
90
|
-
#
|
91
|
-
# The array of names of environments where destructive actions should be prohibited. By default,
|
92
|
-
# the value is <tt>["production"]</tt>.
|
93
|
-
|
94
|
-
##
|
95
|
-
# :singleton-method: protected_environments=
|
96
|
-
# :call-seq: protected_environments=(environments)
|
97
|
-
#
|
98
|
-
# Sets an array of names of environments where destructive actions should be prohibited.
|
99
|
-
|
100
87
|
##
|
101
88
|
# :singleton-method: pluralize_table_names
|
102
89
|
# :call-seq: pluralize_table_names
|
@@ -113,20 +100,6 @@ module ActiveRecord
|
|
113
100
|
# If true, the default table name for a Product class will be "products". If false, it would just be "product".
|
114
101
|
# See table_name for the full rules on table/class naming. This is true, by default.
|
115
102
|
|
116
|
-
##
|
117
|
-
# :singleton-method: ignored_columns
|
118
|
-
# :call-seq: ignored_columns
|
119
|
-
#
|
120
|
-
# The list of columns names the model should ignore. Ignored columns won't have attribute
|
121
|
-
# accessors defined, and won't be referenced in SQL queries.
|
122
|
-
|
123
|
-
##
|
124
|
-
# :singleton-method: ignored_columns=
|
125
|
-
# :call-seq: ignored_columns=(columns)
|
126
|
-
#
|
127
|
-
# Sets the columns names the model should ignore. Ignored columns won't have attribute
|
128
|
-
# accessors defined, and won't be referenced in SQL queries.
|
129
|
-
|
130
103
|
included do
|
131
104
|
mattr_accessor :primary_key_prefix_type, instance_writer: false
|
132
105
|
|
@@ -142,16 +115,12 @@ module ActiveRecord
|
|
142
115
|
class_attribute :internal_metadata_table_name, instance_accessor: false
|
143
116
|
self.internal_metadata_table_name = "ar_internal_metadata"
|
144
117
|
|
145
|
-
class_attribute :protected_environments, instance_accessor: false
|
146
|
-
self.protected_environments = ["production"]
|
147
|
-
|
148
118
|
class_attribute :pluralize_table_names, instance_writer: false
|
149
119
|
self.pluralize_table_names = true
|
150
120
|
|
151
|
-
|
152
|
-
self.ignored_columns = [].freeze
|
153
|
-
|
121
|
+
self.protected_environments = ["production"]
|
154
122
|
self.inheritance_column = "type"
|
123
|
+
self.ignored_columns = [].freeze
|
155
124
|
|
156
125
|
delegate :type_for_attribute, to: :class
|
157
126
|
|
@@ -263,6 +232,21 @@ module ActiveRecord
|
|
263
232
|
(parents.detect { |p| p.respond_to?(:table_name_suffix) } || self).table_name_suffix
|
264
233
|
end
|
265
234
|
|
235
|
+
# The array of names of environments where destructive actions should be prohibited. By default,
|
236
|
+
# the value is <tt>["production"]</tt>.
|
237
|
+
def protected_environments
|
238
|
+
if defined?(@protected_environments)
|
239
|
+
@protected_environments
|
240
|
+
else
|
241
|
+
superclass.protected_environments
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Sets an array of names of environments where destructive actions should be prohibited.
|
246
|
+
def protected_environments=(environments)
|
247
|
+
@protected_environments = environments.map(&:to_s)
|
248
|
+
end
|
249
|
+
|
266
250
|
# Defines the name of the table column which will store the class name on single-table
|
267
251
|
# inheritance situations.
|
268
252
|
#
|
@@ -282,6 +266,22 @@ module ActiveRecord
|
|
282
266
|
@explicit_inheritance_column = true
|
283
267
|
end
|
284
268
|
|
269
|
+
# The list of columns names the model should ignore. Ignored columns won't have attribute
|
270
|
+
# accessors defined, and won't be referenced in SQL queries.
|
271
|
+
def ignored_columns
|
272
|
+
if defined?(@ignored_columns)
|
273
|
+
@ignored_columns
|
274
|
+
else
|
275
|
+
superclass.ignored_columns
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Sets the columns names the model should ignore. Ignored columns won't have attribute
|
280
|
+
# accessors defined, and won't be referenced in SQL queries.
|
281
|
+
def ignored_columns=(columns)
|
282
|
+
@ignored_columns = columns.map(&:to_s)
|
283
|
+
end
|
284
|
+
|
285
285
|
def sequence_name
|
286
286
|
if base_class == self
|
287
287
|
@sequence_name ||= reset_sequence_name
|
@@ -267,11 +267,7 @@ module ActiveRecord
|
|
267
267
|
verify_readonly_attribute(name)
|
268
268
|
public_send("#{name}=", value)
|
269
269
|
|
270
|
-
|
271
|
-
save(validate: false)
|
272
|
-
else
|
273
|
-
true
|
274
|
-
end
|
270
|
+
save(validate: false)
|
275
271
|
end
|
276
272
|
|
277
273
|
# Updates the attributes of the model from the passed-in hash and saves the
|
@@ -5,20 +5,20 @@ module ActiveRecord
|
|
5
5
|
# Enable the query cache within the block if Active Record is configured.
|
6
6
|
# If it's not, it will execute the given block.
|
7
7
|
def cache(&block)
|
8
|
-
if
|
9
|
-
connection.cache(&block)
|
10
|
-
else
|
8
|
+
if configurations.empty?
|
11
9
|
yield
|
10
|
+
else
|
11
|
+
connection.cache(&block)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
15
|
# Disable the query cache within the block if Active Record is configured.
|
16
16
|
# If it's not, it will execute the given block.
|
17
17
|
def uncached(&block)
|
18
|
-
if
|
19
|
-
connection.uncached(&block)
|
20
|
-
else
|
18
|
+
if configurations.empty?
|
21
19
|
yield
|
20
|
+
else
|
21
|
+
connection.uncached(&block)
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|