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.

Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +151 -0
  3. data/lib/active_record/associations/belongs_to_association.rb +2 -2
  4. data/lib/active_record/associations/builder/belongs_to.rb +7 -3
  5. data/lib/active_record/associations/has_many_association.rb +1 -1
  6. data/lib/active_record/associations/join_dependency.rb +3 -3
  7. data/lib/active_record/associations/join_dependency/join_association.rb +1 -9
  8. data/lib/active_record/associations/preloader/association.rb +11 -34
  9. data/lib/active_record/associations/preloader/through_association.rb +10 -3
  10. data/lib/active_record/attribute_methods/dirty.rb +3 -2
  11. data/lib/active_record/collection_cache_key.rb +2 -2
  12. data/lib/active_record/connection_adapters/abstract/query_cache.rb +1 -0
  13. data/lib/active_record/connection_adapters/abstract/schema_creation.rb +1 -1
  14. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +1 -1
  15. data/lib/active_record/connection_adapters/abstract_adapter.rb +2 -1
  16. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +5 -4
  17. data/lib/active_record/connection_adapters/column.rb +1 -1
  18. data/lib/active_record/connection_adapters/mysql/schema_dumper.rb +7 -0
  19. data/lib/active_record/connection_adapters/postgresql/column.rb +28 -1
  20. data/lib/active_record/connection_adapters/postgresql/quoting.rb +1 -1
  21. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +2 -1
  22. data/lib/active_record/connection_adapters/postgresql_adapter.rb +5 -3
  23. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +11 -4
  24. data/lib/active_record/gem_version.rb +2 -2
  25. data/lib/active_record/locking/pessimistic.rb +1 -1
  26. data/lib/active_record/log_subscriber.rb +3 -4
  27. data/lib/active_record/migration/compatibility.rb +34 -20
  28. data/lib/active_record/model_schema.rb +33 -33
  29. data/lib/active_record/persistence.rb +1 -5
  30. data/lib/active_record/query_cache.rb +6 -6
  31. data/lib/active_record/railties/databases.rake +2 -2
  32. data/lib/active_record/reflection.rb +24 -10
  33. data/lib/active_record/relation.rb +14 -2
  34. data/lib/active_record/relation/calculations.rb +16 -11
  35. data/lib/active_record/relation/finder_methods.rb +1 -11
  36. data/lib/active_record/relation/query_methods.rb +19 -14
  37. data/lib/active_record/tasks/database_tasks.rb +11 -10
  38. 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\('"?#{table_name}_#{name}_seq"?'::regclass\)\z} === default_function
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)
@@ -159,7 +159,8 @@ module ActiveRecord
159
159
  table_name,
160
160
  default_function,
161
161
  collation,
162
- comment: comment.presence
162
+ comment: comment.presence,
163
+ max_identifier_length: max_identifier_length
163
164
  )
164
165
  end
165
166
 
@@ -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", "~> 0.18"
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 table_alias_length
368
+ def max_identifier_length
368
369
  @max_identifier_length ||= query_value("SHOW max_identifier_length", "SCHEMA").to_i
369
370
  end
370
- alias index_name_length table_alias_length
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
- @definition.primary_key(from_primary_key) if from_primary_key.present?
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
@@ -7,8 +7,8 @@ module ActiveRecord
7
7
  module VERSION
8
8
  MAJOR = 5
9
9
  MINOR = 1
10
- TINY = 4
11
- PRE = nil
10
+ TINY = 5
11
+ PRE = "rc1"
12
12
 
13
13
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
14
14
  end
@@ -60,7 +60,7 @@ module ActiveRecord
60
60
  # the locked record.
61
61
  def lock!(lock = true)
62
62
  if persisted?
63
- if changed?
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[:binds], payload[:type_casted_binds])
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
- def type_casted_binds(binds, casted_binds)
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(table_name, options) do |t|
46
- class << t
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(table_name, options) do |t|
59
- class << t
60
- prepend TableDefinition
61
- end
62
- yield t
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(table_name, options) do |t|
92
- class << t
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(table_name, options) do |t|
105
- class << t
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
- class_attribute :ignored_columns, instance_accessor: false
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
- if has_changes_to_save?
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 connected?
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 connected?
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