activerecord 5.2.0 → 5.2.8.1

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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +361 -0
  3. data/lib/active_record/association_relation.rb +3 -3
  4. data/lib/active_record/associations/alias_tracker.rb +1 -1
  5. data/lib/active_record/associations/association.rb +25 -10
  6. data/lib/active_record/associations/belongs_to_association.rb +14 -5
  7. data/lib/active_record/associations/belongs_to_polymorphic_association.rb +4 -1
  8. data/lib/active_record/associations/builder/belongs_to.rb +11 -2
  9. data/lib/active_record/associations/builder/collection_association.rb +2 -2
  10. data/lib/active_record/associations/collection_association.rb +19 -15
  11. data/lib/active_record/associations/collection_proxy.rb +8 -34
  12. data/lib/active_record/associations/has_many_association.rb +9 -0
  13. data/lib/active_record/associations/has_many_through_association.rb +29 -12
  14. data/lib/active_record/associations/has_one_association.rb +8 -0
  15. data/lib/active_record/associations/has_one_through_association.rb +5 -1
  16. data/lib/active_record/associations/join_dependency/join_association.rb +39 -24
  17. data/lib/active_record/associations/join_dependency/join_part.rb +7 -0
  18. data/lib/active_record/associations/join_dependency.rb +39 -64
  19. data/lib/active_record/associations/preloader.rb +1 -1
  20. data/lib/active_record/associations/singular_association.rb +4 -10
  21. data/lib/active_record/associations/through_association.rb +1 -1
  22. data/lib/active_record/associations.rb +9 -9
  23. data/lib/active_record/attribute_methods/dirty.rb +15 -10
  24. data/lib/active_record/attribute_methods/read.rb +1 -1
  25. data/lib/active_record/autosave_association.rb +27 -8
  26. data/lib/active_record/callbacks.rb +4 -0
  27. data/lib/active_record/coders/yaml_column.rb +13 -1
  28. data/lib/active_record/collection_cache_key.rb +2 -2
  29. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +36 -11
  30. data/lib/active_record/connection_adapters/abstract/database_limits.rb +5 -0
  31. data/lib/active_record/connection_adapters/abstract/database_statements.rb +19 -6
  32. data/lib/active_record/connection_adapters/abstract/query_cache.rb +8 -3
  33. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -0
  34. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +7 -4
  35. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +6 -15
  36. data/lib/active_record/connection_adapters/abstract/transaction.rb +23 -14
  37. data/lib/active_record/connection_adapters/abstract_adapter.rb +3 -1
  38. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +18 -19
  39. data/lib/active_record/connection_adapters/connection_specification.rb +2 -2
  40. data/lib/active_record/connection_adapters/determine_if_preparable_visitor.rb +11 -2
  41. data/lib/active_record/connection_adapters/mysql/database_statements.rb +36 -0
  42. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +2 -2
  43. data/lib/active_record/connection_adapters/postgresql/oid/array.rb +11 -1
  44. data/lib/active_record/connection_adapters/postgresql/oid/money.rb +2 -2
  45. data/lib/active_record/connection_adapters/postgresql/oid/range.rb +4 -0
  46. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +36 -0
  47. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +12 -26
  48. data/lib/active_record/connection_adapters/postgresql/utils.rb +1 -1
  49. data/lib/active_record/connection_adapters/postgresql_adapter.rb +9 -1
  50. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +5 -0
  51. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +5 -1
  52. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +3 -6
  53. data/lib/active_record/core.rb +12 -1
  54. data/lib/active_record/counter_cache.rb +17 -13
  55. data/lib/active_record/enum.rb +1 -0
  56. data/lib/active_record/errors.rb +18 -12
  57. data/lib/active_record/gem_version.rb +2 -2
  58. data/lib/active_record/log_subscriber.rb +1 -1
  59. data/lib/active_record/migration/compatibility.rb +15 -15
  60. data/lib/active_record/migration.rb +1 -1
  61. data/lib/active_record/model_schema.rb +1 -1
  62. data/lib/active_record/persistence.rb +6 -5
  63. data/lib/active_record/query_cache.rb +4 -11
  64. data/lib/active_record/querying.rb +1 -1
  65. data/lib/active_record/railtie.rb +19 -3
  66. data/lib/active_record/reflection.rb +10 -14
  67. data/lib/active_record/relation/calculations.rb +16 -12
  68. data/lib/active_record/relation/delegation.rb +30 -0
  69. data/lib/active_record/relation/finder_methods.rb +10 -8
  70. data/lib/active_record/relation/merger.rb +10 -11
  71. data/lib/active_record/relation/predicate_builder/array_handler.rb +2 -2
  72. data/lib/active_record/relation/predicate_builder.rb +20 -14
  73. data/lib/active_record/relation/query_attribute.rb +5 -3
  74. data/lib/active_record/relation/query_methods.rb +50 -22
  75. data/lib/active_record/relation/spawn_methods.rb +1 -1
  76. data/lib/active_record/relation.rb +39 -20
  77. data/lib/active_record/scoping/default.rb +2 -2
  78. data/lib/active_record/scoping/named.rb +2 -0
  79. data/lib/active_record/statement_cache.rb +2 -2
  80. data/lib/active_record/tasks/database_tasks.rb +1 -1
  81. data/lib/active_record/timestamp.rb +8 -1
  82. data/lib/active_record/transactions.rb +24 -21
  83. data/lib/active_record/type/serialized.rb +4 -0
  84. metadata +12 -13
@@ -80,8 +80,8 @@ module ActiveRecord
80
80
 
81
81
  def new_column_from_field(table_name, field)
82
82
  type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
83
- if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\(\))?\z/i.match?(field[:Default])
84
- default, default_function = nil, "CURRENT_TIMESTAMP"
83
+ if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(field[:Default])
84
+ default, default_function = nil, field[:Default]
85
85
  else
86
86
  default, default_function = field[:Default], nil
87
87
  end
@@ -33,7 +33,13 @@ module ActiveRecord
33
33
 
34
34
  def cast(value)
35
35
  if value.is_a?(::String)
36
- value = @pg_decoder.decode(value)
36
+ value = begin
37
+ @pg_decoder.decode(value)
38
+ rescue TypeError
39
+ # malformed array string is treated as [], will raise in PG 2.0 gem
40
+ # this keeps a consistent implementation
41
+ []
42
+ end
37
43
  end
38
44
  type_cast_array(value, :cast)
39
45
  end
@@ -66,6 +72,10 @@ module ActiveRecord
66
72
  deserialize(raw_old_value) != new_value
67
73
  end
68
74
 
75
+ def force_equality?(value)
76
+ value.is_a?(::Array)
77
+ end
78
+
69
79
  private
70
80
 
71
81
  def type_cast_array(value, method)
@@ -26,9 +26,9 @@ module ActiveRecord
26
26
 
27
27
  value = value.sub(/^\((.+)\)$/, '-\1') # (4)
28
28
  case value
29
- when /^-?\D+[\d,]+\.\d{2}$/ # (1)
29
+ when /^-?\D*+[\d,]+\.\d{2}$/ # (1)
30
30
  value.gsub!(/[^-\d.]/, "")
31
- when /^-?\D+[\d.]+,\d{2}$/ # (2)
31
+ when /^-?\D*+[\d.]+,\d{2}$/ # (2)
32
32
  value.gsub!(/[^-\d,]/, "").sub!(/,/, ".")
33
33
  end
34
34
 
@@ -53,6 +53,10 @@ module ActiveRecord
53
53
  ::Range.new(new_begin, new_end, value.exclude_end?)
54
54
  end
55
55
 
56
+ def force_equality?(value)
57
+ value.is_a?(::Range)
58
+ end
59
+
56
60
  private
57
61
 
58
62
  def type_cast_single(value)
@@ -17,6 +17,42 @@ module ActiveRecord
17
17
  "VALIDATE CONSTRAINT #{quote_column_name(name)}"
18
18
  end
19
19
 
20
+ def visit_ChangeColumnDefinition(o)
21
+ column = o.column
22
+ column.sql_type = type_to_sql(column.type, column.options)
23
+ quoted_column_name = quote_column_name(o.name)
24
+
25
+ change_column_sql = "ALTER COLUMN #{quoted_column_name} TYPE #{column.sql_type}".dup
26
+
27
+ options = column_options(column)
28
+
29
+ if options[:collation]
30
+ change_column_sql << " COLLATE \"#{options[:collation]}\""
31
+ end
32
+
33
+ if options[:using]
34
+ change_column_sql << " USING #{options[:using]}"
35
+ elsif options[:cast_as]
36
+ cast_as_type = type_to_sql(options[:cast_as], options)
37
+ change_column_sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
38
+ end
39
+
40
+ if options.key?(:default)
41
+ if options[:default].nil?
42
+ change_column_sql << ", ALTER COLUMN #{quoted_column_name} DROP DEFAULT"
43
+ else
44
+ quoted_default = quote_default_expression(options[:default], column)
45
+ change_column_sql << ", ALTER COLUMN #{quoted_column_name} SET DEFAULT #{quoted_default}"
46
+ end
47
+ end
48
+
49
+ if options.key?(:null)
50
+ change_column_sql << ", ALTER COLUMN #{quoted_column_name} #{options[:null] ? 'DROP' : 'SET'} NOT NULL"
51
+ end
52
+
53
+ change_column_sql
54
+ end
55
+
20
56
  def add_column_options!(sql, options)
21
57
  if options[:collation]
22
58
  sql << " COLLATE \"#{options[:collation]}\""
@@ -124,7 +124,7 @@ module ActiveRecord
124
124
 
125
125
  # add info on sort order (only desc order is explicitly specified, asc is the default)
126
126
  # and non-default opclasses
127
- expressions.scan(/(?<column>\w+)\s?(?<opclass>\w+_ops)?\s?(?<desc>DESC)?\s?(?<nulls>NULLS (?:FIRST|LAST))?/).each do |column, opclass, desc, nulls|
127
+ expressions.scan(/(?<column>\w+)"?\s?(?<opclass>\w+_ops)?\s?(?<desc>DESC)?\s?(?<nulls>NULLS (?:FIRST|LAST))?/).each do |column, opclass, desc, nulls|
128
128
  opclasses[column] = opclass.to_sym if opclass
129
129
  if nulls
130
130
  orders[column] = [desc, nulls].compact.join(" ")
@@ -683,34 +683,20 @@ module ActiveRecord
683
683
  end
684
684
  end
685
685
 
686
- def change_column_sql(table_name, column_name, type, options = {})
687
- quoted_column_name = quote_column_name(column_name)
688
- sql_type = type_to_sql(type, options)
689
- sql = "ALTER COLUMN #{quoted_column_name} TYPE #{sql_type}".dup
690
- if options[:collation]
691
- sql << " COLLATE \"#{options[:collation]}\""
692
- end
693
- if options[:using]
694
- sql << " USING #{options[:using]}"
695
- elsif options[:cast_as]
696
- cast_as_type = type_to_sql(options[:cast_as], options)
697
- sql << " USING CAST(#{quoted_column_name} AS #{cast_as_type})"
698
- end
699
-
700
- sql
686
+ def add_column_for_alter(table_name, column_name, type, options = {})
687
+ return super unless options.key?(:comment)
688
+ [super, Proc.new { change_column_comment(table_name, column_name, options[:comment]) }]
701
689
  end
702
690
 
703
691
  def change_column_for_alter(table_name, column_name, type, options = {})
704
- sqls = [change_column_sql(table_name, column_name, type, options)]
705
- sqls << change_column_default_for_alter(table_name, column_name, options[:default]) if options.key?(:default)
706
- sqls << change_column_null_for_alter(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
692
+ td = create_table_definition(table_name)
693
+ cd = td.new_column_definition(column_name, type, options)
694
+ sqls = [schema_creation.accept(ChangeColumnDefinition.new(cd, column_name))]
707
695
  sqls << Proc.new { change_column_comment(table_name, column_name, options[:comment]) } if options.key?(:comment)
708
696
  sqls
709
697
  end
710
698
 
711
-
712
- # Changes the default value of a table column.
713
- def change_column_default_for_alter(table_name, column_name, default_or_changes) # :nodoc:
699
+ def change_column_default_for_alter(table_name, column_name, default_or_changes)
714
700
  column = column_for(table_name, column_name)
715
701
  return unless column
716
702
 
@@ -725,8 +711,8 @@ module ActiveRecord
725
711
  end
726
712
  end
727
713
 
728
- def change_column_null_for_alter(table_name, column_name, null, default = nil) #:nodoc:
729
- "ALTER #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
714
+ def change_column_null_for_alter(table_name, column_name, null, default = nil)
715
+ "ALTER COLUMN #{quote_column_name(column_name)} #{null ? 'DROP' : 'SET'} NOT NULL"
730
716
  end
731
717
 
732
718
  def add_timestamps_for_alter(table_name, options = {})
@@ -751,7 +737,7 @@ module ActiveRecord
751
737
 
752
738
  def data_source_sql(name = nil, type: nil)
753
739
  scope = quoted_scope(name, type: type)
754
- scope[:type] ||= "'r','v','m','f'" # (r)elation/table, (v)iew, (m)aterialized view, (f)oreign table
740
+ scope[:type] ||= "'r','v','m','p','f'" # (r)elation/table, (v)iew, (m)aterialized view, (p)artitioned table, (f)oreign table
755
741
 
756
742
  sql = "SELECT c.relname FROM pg_class c LEFT JOIN pg_namespace n ON n.oid = c.relnamespace".dup
757
743
  sql << " WHERE n.nspname = #{scope[:schema]}"
@@ -765,7 +751,7 @@ module ActiveRecord
765
751
  type = \
766
752
  case type
767
753
  when "BASE TABLE"
768
- "'r'"
754
+ "'r','p'"
769
755
  when "VIEW"
770
756
  "'v','m'"
771
757
  when "FOREIGN TABLE"
@@ -68,7 +68,7 @@ module ActiveRecord
68
68
  # * <tt>"schema_name".table_name</tt>
69
69
  # * <tt>"schema.name"."table name"</tt>
70
70
  def extract_schema_qualified_name(string)
71
- schema, table = string.scan(/[^".\s]+|"[^"]*"/)
71
+ schema, table = string.scan(/[^".]+|"[^"]*"/)
72
72
  if table.nil?
73
73
  table = schema
74
74
  schema = nil
@@ -4,6 +4,14 @@
4
4
  gem "pg", ">= 0.18", "< 2.0"
5
5
  require "pg"
6
6
 
7
+ # Use async_exec instead of exec_params on pg versions before 1.1
8
+ class ::PG::Connection
9
+ unless self.public_method_defined?(:async_exec_params)
10
+ remove_method :exec_params
11
+ alias exec_params async_exec
12
+ end
13
+ end
14
+
7
15
  require "active_record/connection_adapters/abstract_adapter"
8
16
  require "active_record/connection_adapters/statement_pool"
9
17
  require "active_record/connection_adapters/postgresql/column"
@@ -600,7 +608,7 @@ module ActiveRecord
600
608
  type_casted_binds = type_casted_binds(binds)
601
609
  log(sql, name, binds, type_casted_binds) do
602
610
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
603
- @connection.async_exec(sql, type_casted_binds)
611
+ @connection.exec_params(sql, type_casted_binds)
604
612
  end
605
613
  end
606
614
  end
@@ -12,11 +12,16 @@ module ActiveRecord
12
12
  quote_column_name(attr)
13
13
  end
14
14
 
15
+ def quote_table_name(name)
16
+ @quoted_table_names[name] ||= super.gsub(".", "\".\"").freeze
17
+ end
18
+
15
19
  def quote_column_name(name)
16
20
  @quoted_column_names[name] ||= %Q("#{super.gsub('"', '""')}").freeze
17
21
  end
18
22
 
19
23
  def quoted_time(value)
24
+ value = value.change(year: 2000, month: 1, day: 1)
20
25
  quoted_date(value).sub(/\A\d\d\d\d-\d\d-\d\d /, "2000-01-01 ")
21
26
  end
22
27
 
@@ -7,6 +7,10 @@ module ActiveRecord
7
7
  # Returns an array of indexes for the given table.
8
8
  def indexes(table_name)
9
9
  exec_query("PRAGMA index_list(#{quote_table_name(table_name)})", "SCHEMA").map do |row|
10
+ # Indexes SQLite creates implicitly for internal use start with "sqlite_".
11
+ # See https://www.sqlite.org/fileformat2.html#intschema
12
+ next if row["name"].starts_with?("sqlite_")
13
+
10
14
  index_sql = query_value(<<-SQL, "SCHEMA")
11
15
  SELECT sql
12
16
  FROM sqlite_master
@@ -40,7 +44,7 @@ module ActiveRecord
40
44
  where: where,
41
45
  orders: orders
42
46
  )
43
- end
47
+ end.compact
44
48
  end
45
49
 
46
50
  def create_schema_dumper(options)
@@ -9,7 +9,7 @@ require "active_record/connection_adapters/sqlite3/schema_definitions"
9
9
  require "active_record/connection_adapters/sqlite3/schema_dumper"
10
10
  require "active_record/connection_adapters/sqlite3/schema_statements"
11
11
 
12
- gem "sqlite3", "~> 1.3.6"
12
+ gem "sqlite3", "~> 1.3", ">= 1.3.6"
13
13
  require "sqlite3"
14
14
 
15
15
  module ActiveRecord
@@ -453,9 +453,6 @@ module ActiveRecord
453
453
  def copy_table_indexes(from, to, rename = {})
454
454
  indexes(from).each do |index|
455
455
  name = index.name
456
- # indexes sqlite creates for internal use start with `sqlite_` and
457
- # don't need to be copied
458
- next if name.starts_with?("sqlite_")
459
456
  if to == "a#{from}"
460
457
  name = "t#{name}"
461
458
  elsif from == "a#{to}"
@@ -528,9 +525,9 @@ module ActiveRecord
528
525
  result = exec_query(sql, "SCHEMA").first
529
526
 
530
527
  if result
531
- # Splitting with left parentheses and picking up last will return all
528
+ # Splitting with left parentheses and discarding the first part will return all
532
529
  # columns separated with comma(,).
533
- columns_string = result["sql"].split("(").last
530
+ columns_string = result["sql"].split("(", 2).last
534
531
 
535
532
  columns_string.split(",").each do |column_string|
536
533
  # This regex will match the column name and collation type and will save
@@ -125,6 +125,16 @@ module ActiveRecord
125
125
 
126
126
  mattr_accessor :belongs_to_required_by_default, instance_accessor: false
127
127
 
128
+ ##
129
+ # :singleton-method:
130
+ # Application configurable boolean that instructs the YAML Coder to use
131
+ # an unsafe load if set to true.
132
+ mattr_accessor :use_yaml_unsafe_load, instance_writer: false, default: false
133
+
134
+ # Application configurable array that provides additional permitted classes
135
+ # to Psych safe_load in the YAML Coder
136
+ mattr_accessor :yaml_column_permitted_classes, instance_writer: false, default: []
137
+
128
138
  class_attribute :default_connection_handler, instance_writer: false
129
139
 
130
140
  def self.connection_handler
@@ -184,7 +194,8 @@ module ActiveRecord
184
194
  end
185
195
 
186
196
  def find_by(*args) # :nodoc:
187
- return super if scope_attributes? || reflect_on_all_aggregations.any?
197
+ return super if scope_attributes? || reflect_on_all_aggregations.any? ||
198
+ columns_hash.key?(inheritance_column) && base_class != self
188
199
 
189
200
  hash = args.first
190
201
 
@@ -47,8 +47,12 @@ module ActiveRecord
47
47
  reflection = child_class._reflections.values.find { |e| e.belongs_to? && e.foreign_key.to_s == foreign_key && e.options[:counter_cache].present? }
48
48
  counter_name = reflection.counter_cache_column
49
49
 
50
- updates = { counter_name.to_sym => object.send(counter_association).count(:all) }
51
- updates.merge!(touch_updates(touch)) if touch
50
+ updates = { counter_name => object.send(counter_association).count(:all) }
51
+
52
+ if touch
53
+ names = touch if touch != true
54
+ updates.merge!(touch_attributes_with_time(*names))
55
+ end
52
56
 
53
57
  unscoped.where(primary_key => object.id).update_all(updates)
54
58
  end
@@ -68,8 +72,8 @@ module ActiveRecord
68
72
  # * +counters+ - A Hash containing the names of the fields
69
73
  # to update as keys and the amount to update the field by as values.
70
74
  # * <tt>:touch</tt> option - Touch timestamp columns when updating.
71
- # Pass +true+ to touch +updated_at+ and/or +updated_on+. Pass a symbol to
72
- # touch that column or an array of symbols to touch just those ones.
75
+ # If attribute names are passed, they are updated along with updated_at/on
76
+ # attributes.
73
77
  #
74
78
  # ==== Examples
75
79
  #
@@ -107,11 +111,18 @@ module ActiveRecord
107
111
  end
108
112
 
109
113
  if touch
110
- touch_updates = touch_updates(touch)
114
+ names = touch if touch != true
115
+ touch_updates = touch_attributes_with_time(*names)
111
116
  updates << sanitize_sql_for_assignment(touch_updates) unless touch_updates.empty?
112
117
  end
113
118
 
114
- unscoped.where(primary_key => id).update_all updates.join(", ")
119
+ if id.is_a?(Relation) && self == id.klass
120
+ relation = id
121
+ else
122
+ relation = unscoped.where!(primary_key => id)
123
+ end
124
+
125
+ relation.update_all updates.join(", ")
115
126
  end
116
127
 
117
128
  # Increment a numeric field by one, via a direct SQL update.
@@ -165,13 +176,6 @@ module ActiveRecord
165
176
  def decrement_counter(counter_name, id, touch: nil)
166
177
  update_counters(id, counter_name => -1, touch: touch)
167
178
  end
168
-
169
- private
170
- def touch_updates(touch)
171
- touch = timestamp_attributes_for_update_in_model if touch == true
172
- touch_time = current_time_from_proper_timezone
173
- Array(touch).map { |column| [ column, touch_time ] }.to_h
174
- end
175
179
  end
176
180
 
177
181
  private
@@ -201,6 +201,7 @@ module ActiveRecord
201
201
  klass.scope value_method_name, -> { where(attr => value) }
202
202
  end
203
203
  end
204
+ enum_values.freeze
204
205
  end
205
206
  end
206
207
 
@@ -117,16 +117,27 @@ module ActiveRecord
117
117
 
118
118
  # Raised when a foreign key constraint cannot be added because the column type does not match the referenced column type.
119
119
  class MismatchedForeignKey < StatementInvalid
120
- def initialize(adapter = nil, message: nil, table: nil, foreign_key: nil, target_table: nil, primary_key: nil)
121
- @adapter = adapter
120
+ def initialize(
121
+ adapter = nil,
122
+ message: nil,
123
+ sql: nil,
124
+ binds: nil,
125
+ table: nil,
126
+ foreign_key: nil,
127
+ target_table: nil,
128
+ primary_key: nil,
129
+ primary_key_column: nil
130
+ )
122
131
  if table
123
- msg = <<-EOM.strip_heredoc
124
- Column `#{foreign_key}` on table `#{table}` has a type of `#{column_type(table, foreign_key)}`.
125
- This does not match column `#{primary_key}` on `#{target_table}`, which has type `#{column_type(target_table, primary_key)}`.
126
- To resolve this issue, change the type of the `#{foreign_key}` column on `#{table}` to be :integer. (For example `t.integer #{foreign_key}`).
132
+ type = primary_key_column.bigint? ? :bigint : primary_key_column.type
133
+ msg = <<-EOM.squish
134
+ Column `#{foreign_key}` on table `#{table}` does not match column `#{primary_key}` on `#{target_table}`,
135
+ which has type `#{primary_key_column.sql_type}`.
136
+ To resolve this issue, change the type of the `#{foreign_key}` column on `#{table}` to be :#{type}.
137
+ (For example `t.#{type} :#{foreign_key}`).
127
138
  EOM
128
139
  else
129
- msg = <<-EOM
140
+ msg = <<-EOM.squish
130
141
  There is a mismatch between the foreign key and primary key column types.
131
142
  Verify that the foreign key column type and the primary key of the associated table match types.
132
143
  EOM
@@ -136,11 +147,6 @@ module ActiveRecord
136
147
  end
137
148
  super(msg)
138
149
  end
139
-
140
- private
141
- def column_type(table, column)
142
- @adapter.columns(table).detect { |c| c.name == column }.sql_type
143
- end
144
150
  end
145
151
 
146
152
  # Raised when a record cannot be inserted or updated because it would violate a not null constraint.
@@ -9,8 +9,8 @@ module ActiveRecord
9
9
  module VERSION
10
10
  MAJOR = 5
11
11
  MINOR = 2
12
- TINY = 0
13
- PRE = nil
12
+ TINY = 8
13
+ PRE = "1"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -125,7 +125,7 @@ module ActiveRecord
125
125
  ]
126
126
  end
127
127
 
128
- RAILS_GEM_ROOT = File.expand_path("../../../..", __FILE__) + "/"
128
+ RAILS_GEM_ROOT = File.expand_path("../../..", __dir__) + "/"
129
129
 
130
130
  def ignored_callstack(path)
131
131
  path.start_with?(RAILS_GEM_ROOT) ||
@@ -17,20 +17,18 @@ module ActiveRecord
17
17
 
18
18
  class V5_1 < V5_2
19
19
  def change_column(table_name, column_name, type, options = {})
20
- if adapter_name == "PostgreSQL"
21
- clear_cache!
22
- sql = connection.send(:change_column_sql, table_name, column_name, type, options)
23
- execute "ALTER TABLE #{quote_table_name(table_name)} #{sql}"
24
- change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
25
- change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
26
- change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
20
+ if connection.adapter_name == "PostgreSQL"
21
+ super(table_name, column_name, type, options.except(:default, :null, :comment))
22
+ connection.change_column_default(table_name, column_name, options[:default]) if options.key?(:default)
23
+ connection.change_column_null(table_name, column_name, options[:null], options[:default]) if options.key?(:null)
24
+ connection.change_column_comment(table_name, column_name, options[:comment]) if options.key?(:comment)
27
25
  else
28
26
  super
29
27
  end
30
28
  end
31
29
 
32
30
  def create_table(table_name, options = {})
33
- if adapter_name == "Mysql2"
31
+ if connection.adapter_name == "Mysql2"
34
32
  super(table_name, options: "ENGINE=InnoDB", **options)
35
33
  else
36
34
  super
@@ -52,13 +50,13 @@ module ActiveRecord
52
50
  end
53
51
 
54
52
  def create_table(table_name, options = {})
55
- if adapter_name == "PostgreSQL"
53
+ if connection.adapter_name == "PostgreSQL"
56
54
  if options[:id] == :uuid && !options.key?(:default)
57
55
  options[:default] = "uuid_generate_v4()"
58
56
  end
59
57
  end
60
58
 
61
- unless adapter_name == "Mysql2" && options[:id] == :bigint
59
+ unless connection.adapter_name == "Mysql2" && options[:id] == :bigint
62
60
  if [:integer, :bigint].include?(options[:id]) && !options.key?(:default)
63
61
  options[:default] = nil
64
62
  end
@@ -175,7 +173,7 @@ module ActiveRecord
175
173
  if options[:name].present?
176
174
  options[:name].to_s
177
175
  else
178
- index_name(table_name, column: column_names)
176
+ connection.index_name(table_name, column: column_names)
179
177
  end
180
178
  super
181
179
  end
@@ -195,15 +193,17 @@ module ActiveRecord
195
193
  end
196
194
 
197
195
  def index_name_for_remove(table_name, options = {})
198
- index_name = index_name(table_name, options)
196
+ index_name = connection.index_name(table_name, options)
199
197
 
200
- unless index_name_exists?(table_name, index_name)
198
+ unless connection.index_name_exists?(table_name, index_name)
201
199
  if options.is_a?(Hash) && options.has_key?(:name)
202
200
  options_without_column = options.dup
203
201
  options_without_column.delete :column
204
- index_name_without_column = index_name(table_name, options_without_column)
202
+ index_name_without_column = connection.index_name(table_name, options_without_column)
205
203
 
206
- return index_name_without_column if index_name_exists?(table_name, index_name_without_column)
204
+ if connection.index_name_exists?(table_name, index_name_without_column)
205
+ return index_name_without_column
206
+ end
207
207
  end
208
208
 
209
209
  raise ArgumentError, "Index name '#{index_name}' on table '#{table_name}' does not exist"
@@ -1163,7 +1163,7 @@ module ActiveRecord
1163
1163
 
1164
1164
  def migrations_path=(path)
1165
1165
  ActiveSupport::Deprecation.warn \
1166
- "ActiveRecord::Migrator.migrations_paths= is now deprecated and will be removed in Rails 6.0." \
1166
+ "`ActiveRecord::Migrator.migrations_path=` is now deprecated and will be removed in Rails 6.0. " \
1167
1167
  "You can set the `migrations_paths` on the `connection` instead through the `database.yml`."
1168
1168
  self.migrations_paths = [path]
1169
1169
  end
@@ -375,7 +375,7 @@ module ActiveRecord
375
375
  # default values when instantiating the Active Record object for this table.
376
376
  def column_defaults
377
377
  load_schema
378
- @column_defaults ||= _default_attributes.to_hash
378
+ @column_defaults ||= _default_attributes.deep_dup.to_hash
379
379
  end
380
380
 
381
381
  def _default_attributes # :nodoc:
@@ -373,7 +373,7 @@ module ActiveRecord
373
373
  became = klass.allocate
374
374
  became.send(:initialize)
375
375
  became.instance_variable_set("@attributes", @attributes)
376
- became.instance_variable_set("@mutations_from_database", @mutations_from_database) if defined?(@mutations_from_database)
376
+ became.instance_variable_set("@mutations_from_database", @mutations_from_database ||= nil)
377
377
  became.instance_variable_set("@changed_attributes", attributes_changed_by_setter)
378
378
  became.instance_variable_set("@new_record", new_record?)
379
379
  became.instance_variable_set("@destroyed", destroyed?)
@@ -473,15 +473,16 @@ module ActiveRecord
473
473
  verify_readonly_attribute(key.to_s)
474
474
  end
475
475
 
476
+ id_in_database = self.id_in_database
477
+ attributes.each do |k, v|
478
+ write_attribute_without_type_cast(k, v)
479
+ end
480
+
476
481
  affected_rows = self.class._update_record(
477
482
  attributes,
478
483
  self.class.primary_key => id_in_database
479
484
  )
480
485
 
481
- attributes.each do |k, v|
482
- write_attribute_without_type_cast(k, v)
483
- end
484
-
485
486
  affected_rows == 1
486
487
  end
487
488
 
@@ -26,19 +26,12 @@ module ActiveRecord
26
26
  end
27
27
 
28
28
  def self.run
29
- ActiveRecord::Base.connection_handler.connection_pool_list.map do |pool|
30
- caching_was_enabled = pool.query_cache_enabled
31
-
32
- pool.enable_query_cache!
33
-
34
- [pool, caching_was_enabled]
35
- end
29
+ ActiveRecord::Base.connection_handler.connection_pool_list.
30
+ reject { |p| p.query_cache_enabled }.each { |p| p.enable_query_cache! }
36
31
  end
37
32
 
38
- def self.complete(caching_pools)
39
- caching_pools.each do |pool, caching_was_enabled|
40
- pool.disable_query_cache! unless caching_was_enabled
41
- end
33
+ def self.complete(pools)
34
+ pools.each { |pool| pool.disable_query_cache! }
42
35
 
43
36
  ActiveRecord::Base.connection_handler.connection_pool_list.each do |pool|
44
37
  pool.release_connection if pool.active_connection? && !pool.connection.transaction_open?
@@ -40,7 +40,7 @@ module ActiveRecord
40
40
  def find_by_sql(sql, binds = [], preparable: nil, &block)
41
41
  result_set = connection.select_all(sanitize_sql(sql), "#{name} Load", binds, preparable: preparable)
42
42
  column_types = result_set.column_types.dup
43
- columns_hash.each_key { |k| column_types.delete k }
43
+ attribute_types.each_key { |k| column_types.delete k }
44
44
  message_bus = ActiveSupport::Notifications.instrumenter
45
45
 
46
46
  payload = {
@@ -169,9 +169,7 @@ end_warning
169
169
  end
170
170
 
171
171
  initializer "active_record.set_executor_hooks" do
172
- ActiveSupport.on_load(:active_record) do
173
- ActiveRecord::QueryCache.install_executor_hooks
174
- end
172
+ ActiveRecord::QueryCache.install_executor_hooks
175
173
  end
176
174
 
177
175
  initializer "active_record.add_watchable_files" do |app|
@@ -224,5 +222,23 @@ MSG
224
222
  end
225
223
  end
226
224
  end
225
+
226
+ initializer "active_record.use_yaml_unsafe_load" do |app|
227
+ config.after_initialize do
228
+ unless app.config.active_record.use_yaml_unsafe_load.nil?
229
+ ActiveRecord::Base.use_yaml_unsafe_load =
230
+ app.config.active_record.use_yaml_unsafe_load
231
+ end
232
+ end
233
+ end
234
+
235
+ initializer "active_record.yaml_column_permitted_classes" do |app|
236
+ config.after_initialize do
237
+ unless app.config.active_record.yaml_column_permitted_classes.nil?
238
+ ActiveRecord::Base.yaml_column_permitted_classes =
239
+ app.config.active_record.yaml_column_permitted_classes
240
+ end
241
+ end
242
+ end
227
243
  end
228
244
  end