activerecord 7.2.3 → 8.0.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +192 -1261
  3. data/README.rdoc +2 -2
  4. data/lib/active_record/associations/alias_tracker.rb +4 -6
  5. data/lib/active_record/associations/association.rb +25 -5
  6. data/lib/active_record/associations/belongs_to_association.rb +2 -18
  7. data/lib/active_record/associations/builder/association.rb +7 -6
  8. data/lib/active_record/associations/collection_association.rb +4 -4
  9. data/lib/active_record/associations/disable_joins_association_scope.rb +1 -1
  10. data/lib/active_record/associations/has_many_through_association.rb +4 -9
  11. data/lib/active_record/associations/join_dependency/join_association.rb +27 -25
  12. data/lib/active_record/associations/preloader/association.rb +2 -2
  13. data/lib/active_record/associations/singular_association.rb +8 -3
  14. data/lib/active_record/associations.rb +50 -32
  15. data/lib/active_record/asynchronous_queries_tracker.rb +28 -24
  16. data/lib/active_record/attribute_methods/serialization.rb +1 -1
  17. data/lib/active_record/attribute_methods.rb +19 -24
  18. data/lib/active_record/attributes.rb +26 -37
  19. data/lib/active_record/autosave_association.rb +81 -49
  20. data/lib/active_record/base.rb +2 -2
  21. data/lib/active_record/callbacks.rb +1 -1
  22. data/lib/active_record/connection_adapters/abstract/connection_handler.rb +16 -10
  23. data/lib/active_record/connection_adapters/abstract/connection_pool/queue.rb +0 -1
  24. data/lib/active_record/connection_adapters/abstract/connection_pool/reaper.rb +0 -1
  25. data/lib/active_record/connection_adapters/abstract/connection_pool.rb +31 -75
  26. data/lib/active_record/connection_adapters/abstract/database_statements.rb +90 -43
  27. data/lib/active_record/connection_adapters/abstract/query_cache.rb +14 -19
  28. data/lib/active_record/connection_adapters/abstract/quoting.rb +1 -1
  29. data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +2 -6
  30. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +27 -9
  31. data/lib/active_record/connection_adapters/abstract/transaction.rb +15 -5
  32. data/lib/active_record/connection_adapters/abstract_adapter.rb +27 -57
  33. data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +28 -58
  34. data/lib/active_record/connection_adapters/mysql/quoting.rb +1 -15
  35. data/lib/active_record/connection_adapters/mysql/schema_definitions.rb +2 -8
  36. data/lib/active_record/connection_adapters/mysql/schema_statements.rb +43 -45
  37. data/lib/active_record/connection_adapters/mysql2/database_statements.rb +42 -98
  38. data/lib/active_record/connection_adapters/mysql2_adapter.rb +2 -16
  39. data/lib/active_record/connection_adapters/postgresql/database_statements.rb +64 -42
  40. data/lib/active_record/connection_adapters/postgresql/oid/point.rb +10 -0
  41. data/lib/active_record/connection_adapters/postgresql/schema_creation.rb +0 -1
  42. data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +12 -14
  43. data/lib/active_record/connection_adapters/postgresql/schema_dumper.rb +1 -1
  44. data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +51 -9
  45. data/lib/active_record/connection_adapters/postgresql_adapter.rb +44 -101
  46. data/lib/active_record/connection_adapters/schema_cache.rb +1 -3
  47. data/lib/active_record/connection_adapters/sqlite3/database_statements.rb +76 -100
  48. data/lib/active_record/connection_adapters/sqlite3/quoting.rb +0 -13
  49. data/lib/active_record/connection_adapters/sqlite3/schema_creation.rb +0 -6
  50. data/lib/active_record/connection_adapters/sqlite3/schema_dumper.rb +13 -0
  51. data/lib/active_record/connection_adapters/sqlite3/schema_statements.rb +8 -2
  52. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +60 -22
  53. data/lib/active_record/connection_adapters/trilogy/database_statements.rb +37 -67
  54. data/lib/active_record/connection_adapters/trilogy_adapter.rb +1 -18
  55. data/lib/active_record/connection_handling.rb +29 -11
  56. data/lib/active_record/core.rb +15 -60
  57. data/lib/active_record/counter_cache.rb +1 -1
  58. data/lib/active_record/database_configurations/connection_url_resolver.rb +1 -3
  59. data/lib/active_record/delegated_type.rb +18 -18
  60. data/lib/active_record/encryption/config.rb +3 -1
  61. data/lib/active_record/encryption/encryptable_record.rb +5 -5
  62. data/lib/active_record/encryption/encrypted_attribute_type.rb +11 -2
  63. data/lib/active_record/encryption/encryptor.rb +35 -29
  64. data/lib/active_record/encryption/extended_deterministic_queries.rb +4 -2
  65. data/lib/active_record/encryption/scheme.rb +8 -1
  66. data/lib/active_record/enum.rb +12 -13
  67. data/lib/active_record/errors.rb +16 -8
  68. data/lib/active_record/fixture_set/table_row.rb +2 -19
  69. data/lib/active_record/fixtures.rb +0 -1
  70. data/lib/active_record/future_result.rb +14 -10
  71. data/lib/active_record/gem_version.rb +4 -4
  72. data/lib/active_record/insert_all.rb +1 -1
  73. data/lib/active_record/marshalling.rb +1 -4
  74. data/lib/active_record/migration/command_recorder.rb +22 -5
  75. data/lib/active_record/migration/compatibility.rb +5 -2
  76. data/lib/active_record/migration.rb +36 -35
  77. data/lib/active_record/model_schema.rb +1 -1
  78. data/lib/active_record/nested_attributes.rb +4 -6
  79. data/lib/active_record/persistence.rb +128 -130
  80. data/lib/active_record/query_cache.rb +5 -4
  81. data/lib/active_record/query_logs.rb +98 -44
  82. data/lib/active_record/query_logs_formatter.rb +17 -28
  83. data/lib/active_record/querying.rb +10 -10
  84. data/lib/active_record/railtie.rb +5 -6
  85. data/lib/active_record/railties/databases.rake +1 -2
  86. data/lib/active_record/reflection.rb +9 -7
  87. data/lib/active_record/relation/batches/batch_enumerator.rb +4 -3
  88. data/lib/active_record/relation/batches.rb +132 -72
  89. data/lib/active_record/relation/calculations.rb +55 -55
  90. data/lib/active_record/relation/delegation.rb +25 -14
  91. data/lib/active_record/relation/finder_methods.rb +31 -32
  92. data/lib/active_record/relation/merger.rb +8 -8
  93. data/lib/active_record/relation/predicate_builder/association_query_value.rb +0 -2
  94. data/lib/active_record/relation/predicate_builder/polymorphic_array_value.rb +1 -1
  95. data/lib/active_record/relation/predicate_builder/relation_handler.rb +4 -3
  96. data/lib/active_record/relation/predicate_builder.rb +5 -0
  97. data/lib/active_record/relation/query_attribute.rb +1 -1
  98. data/lib/active_record/relation/query_methods.rb +90 -91
  99. data/lib/active_record/relation/record_fetch_warning.rb +2 -2
  100. data/lib/active_record/relation/spawn_methods.rb +1 -1
  101. data/lib/active_record/relation/where_clause.rb +2 -8
  102. data/lib/active_record/relation.rb +77 -76
  103. data/lib/active_record/result.rb +68 -7
  104. data/lib/active_record/sanitization.rb +7 -6
  105. data/lib/active_record/schema_dumper.rb +16 -29
  106. data/lib/active_record/schema_migration.rb +2 -1
  107. data/lib/active_record/scoping/named.rb +5 -2
  108. data/lib/active_record/secure_token.rb +3 -3
  109. data/lib/active_record/signed_id.rb +6 -7
  110. data/lib/active_record/statement_cache.rb +12 -12
  111. data/lib/active_record/store.rb +7 -3
  112. data/lib/active_record/tasks/database_tasks.rb +24 -15
  113. data/lib/active_record/tasks/mysql_database_tasks.rb +0 -2
  114. data/lib/active_record/tasks/postgresql_database_tasks.rb +0 -7
  115. data/lib/active_record/tasks/sqlite_database_tasks.rb +2 -2
  116. data/lib/active_record/test_fixtures.rb +12 -0
  117. data/lib/active_record/testing/query_assertions.rb +2 -2
  118. data/lib/active_record/token_for.rb +1 -1
  119. data/lib/active_record/transactions.rb +1 -3
  120. data/lib/active_record/validations/uniqueness.rb +8 -8
  121. data/lib/active_record.rb +16 -1
  122. data/lib/arel/collectors/bind.rb +1 -1
  123. data/lib/arel/crud.rb +0 -2
  124. data/lib/arel/delete_manager.rb +0 -5
  125. data/lib/arel/nodes/delete_statement.rb +2 -4
  126. data/lib/arel/nodes/update_statement.rb +2 -4
  127. data/lib/arel/select_manager.rb +2 -6
  128. data/lib/arel/update_manager.rb +0 -5
  129. data/lib/arel/visitors/dot.rb +0 -2
  130. data/lib/arel/visitors/sqlite.rb +0 -25
  131. data/lib/arel/visitors/to_sql.rb +1 -3
  132. metadata +14 -11
@@ -22,6 +22,9 @@ module ActiveRecord
22
22
  end
23
23
 
24
24
  module DelegateCache # :nodoc:
25
+ @delegate_base_methods = true
26
+ singleton_class.attr_accessor :delegate_base_methods
27
+
25
28
  def relation_delegate_class(klass)
26
29
  @relation_delegate_cache[klass]
27
30
  end
@@ -75,12 +78,12 @@ module ActiveRecord
75
78
  if /\A[a-zA-Z_]\w*[!?]?\z/.match?(method) && !::ActiveSupport::Delegation::RESERVED_METHOD_NAMES.include?(method.to_s)
76
79
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
77
80
  def #{method}(...)
78
- scoping { klass.#{method}(...) }
81
+ scoping { model.#{method}(...) }
79
82
  end
80
83
  RUBY
81
84
  else
82
85
  define_method(method) do |*args, **kwargs, &block|
83
- scoping { klass.public_send(method, *args, **kwargs, &block) }
86
+ scoping { model.public_send(method, *args, **kwargs, &block) }
84
87
  end
85
88
  end
86
89
  end
@@ -92,15 +95,15 @@ module ActiveRecord
92
95
 
93
96
  # This module creates compiled delegation methods dynamically at runtime, which makes
94
97
  # subsequent calls to that method faster by avoiding method_missing. The delegations
95
- # may vary depending on the klass of a relation, so we create a subclass of Relation
96
- # for each different klass, and the delegations are compiled into that subclass only.
98
+ # may vary depending on the model of a relation, so we create a subclass of Relation
99
+ # for each different model, and the delegations are compiled into that subclass only.
97
100
 
98
101
  delegate :to_xml, :encode_with, :length, :each, :join, :intersect?,
99
102
  :[], :&, :|, :+, :-, :sample, :reverse, :rotate, :compact, :in_groups, :in_groups_of,
100
103
  :to_sentence, :to_fs, :to_formatted_s, :as_json,
101
104
  :shuffle, :split, :slice, :index, :rindex, to: :records
102
105
 
103
- delegate :primary_key, :lease_connection, :connection, :with_connection, :transaction, to: :klass
106
+ delegate :primary_key, :with_connection, :connection, :table_name, :transaction, :sanitize_sql_like, :unscoped, :name, to: :model
104
107
 
105
108
  module ClassSpecificRelation # :nodoc:
106
109
  extend ActiveSupport::Concern
@@ -113,11 +116,19 @@ module ActiveRecord
113
116
 
114
117
  private
115
118
  def method_missing(method, ...)
116
- if @klass.respond_to?(method)
117
- unless Delegation.uncacheable_methods.include?(method)
118
- @klass.generate_relation_method(method)
119
+ if model.respond_to?(method)
120
+ if !DelegateCache.delegate_base_methods && Base.respond_to?(method)
121
+ # A common mistake in Active Record's own code is to call `ActiveRecord::Base`
122
+ # class methods on Association. It works because it's automatically delegated, but
123
+ # can introduce subtle bugs because it sets the global scope.
124
+ # We can't deprecate this behavior because gems might depend on it, however we
125
+ # can ban it from Active Record's own test suite to avoid regressions.
126
+ raise NotImplementedError, "Active Record code shouldn't rely on association delegation into ActiveRecord::Base methods"
127
+ elsif !Delegation.uncacheable_methods.include?(method)
128
+ model.generate_relation_method(method)
119
129
  end
120
- scoping { @klass.public_send(method, ...) }
130
+
131
+ scoping { model.public_send(method, ...) }
121
132
  else
122
133
  super
123
134
  end
@@ -125,19 +136,19 @@ module ActiveRecord
125
136
  end
126
137
 
127
138
  module ClassMethods # :nodoc:
128
- def create(klass, *args, **kwargs)
129
- relation_class_for(klass).new(klass, *args, **kwargs)
139
+ def create(model, ...)
140
+ relation_class_for(model).new(model, ...)
130
141
  end
131
142
 
132
143
  private
133
- def relation_class_for(klass)
134
- klass.relation_delegate_class(self)
144
+ def relation_class_for(model)
145
+ model.relation_delegate_class(self)
135
146
  end
136
147
  end
137
148
 
138
149
  private
139
150
  def respond_to_missing?(method, _)
140
- super || @klass.respond_to?(method)
151
+ super || model.respond_to?(method)
141
152
  end
142
153
  end
143
154
  end
@@ -24,22 +24,22 @@ module ActiveRecord
24
24
  # TravelRoute.primary_key = [:origin, :destination]
25
25
  #
26
26
  # TravelRoute.find(["Ottawa", "London"])
27
- # # => #<TravelRoute origin: "Ottawa", destination: "London">
27
+ # => #<TravelRoute origin: "Ottawa", destination: "London">
28
28
  #
29
29
  # TravelRoute.find([["Paris", "Montreal"]])
30
- # # => [#<TravelRoute origin: "Paris", destination: "Montreal">]
30
+ # => [#<TravelRoute origin: "Paris", destination: "Montreal">]
31
31
  #
32
32
  # TravelRoute.find(["New York", "Las Vegas"], ["New York", "Portland"])
33
- # # => [
34
- # # #<TravelRoute origin: "New York", destination: "Las Vegas">,
35
- # # #<TravelRoute origin: "New York", destination: "Portland">
36
- # # ]
33
+ # => [
34
+ # #<TravelRoute origin: "New York", destination: "Las Vegas">,
35
+ # #<TravelRoute origin: "New York", destination: "Portland">
36
+ # ]
37
37
  #
38
38
  # TravelRoute.find([["Berlin", "London"], ["Barcelona", "Lisbon"]])
39
- # # => [
40
- # # #<TravelRoute origin: "Berlin", destination: "London">,
41
- # # #<TravelRoute origin: "Barcelona", destination: "Lisbon">
42
- # # ]
39
+ # => [
40
+ # #<TravelRoute origin: "Berlin", destination: "London">,
41
+ # #<TravelRoute origin: "Barcelona", destination: "Lisbon">
42
+ # ]
43
43
  #
44
44
  # NOTE: The returned records are in the same order as the ids you provide.
45
45
  # If you want the results to be sorted by database, you can use ActiveRecord::QueryMethods#where
@@ -145,10 +145,10 @@ module ActiveRecord
145
145
 
146
146
  if found.nil?
147
147
  raise_record_not_found_exception!
148
- elsif undesired.present?
149
- raise ActiveRecord::SoleRecordExceeded.new(self)
150
- else
148
+ elsif undesired.nil?
151
149
  found
150
+ else
151
+ raise ActiveRecord::SoleRecordExceeded.new(model)
152
152
  end
153
153
  end
154
154
 
@@ -376,7 +376,7 @@ module ActiveRecord
376
376
 
377
377
  skip_query_cache_if_necessary do
378
378
  with_connection do |c|
379
- c.select_rows(relation.arel, "#{name} Exists?").size == 1
379
+ c.select_rows(relation.arel, "#{model.name} Exists?").size == 1
380
380
  end
381
381
  end
382
382
  end
@@ -389,7 +389,7 @@ module ActiveRecord
389
389
  def include?(record)
390
390
  # The existing implementation relies on receiving an Active Record instance as the input parameter named record.
391
391
  # Any non-Active Record object passed to this implementation is guaranteed to return `false`.
392
- return false unless record.is_a?(klass)
392
+ return false unless record.is_a?(model)
393
393
 
394
394
  if loaded? || offset_value || limit_value || having_clause.any?
395
395
  records.include?(record)
@@ -415,22 +415,21 @@ module ActiveRecord
415
415
  # the expected number of results should be provided in the +expected_size+
416
416
  # argument.
417
417
  def raise_record_not_found_exception!(ids = nil, result_size = nil, expected_size = nil, key = primary_key, not_found_ids = nil) # :nodoc:
418
- conditions = " [#{arel.where_sql(klass)}]" unless where_clause.empty?
418
+ conditions = " [#{arel.where_sql(model)}]" unless where_clause.empty?
419
419
 
420
- name = @klass.name
420
+ name = model.name
421
421
 
422
422
  if ids.nil?
423
423
  error = +"Couldn't find #{name}"
424
424
  error << " with#{conditions}" if conditions
425
425
  raise RecordNotFound.new(error, name, key)
426
426
  elsif Array.wrap(ids).size == 1
427
- id = Array.wrap(ids)[0]
428
- error = "Couldn't find #{name} with '#{key}'=#{id.inspect}#{conditions}"
427
+ error = "Couldn't find #{name} with '#{key}'=#{ids}#{conditions}"
429
428
  raise RecordNotFound.new(error, name, key, ids)
430
429
  else
431
430
  error = +"Couldn't find all #{name.pluralize} with '#{key}': "
432
- error << "(#{ids.map(&:inspect).join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
433
- error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.map(&:inspect).join(', ')}." if not_found_ids
431
+ error << "(#{ids.join(", ")})#{conditions} (found #{result_size} results, but was looking for #{expected_size})."
432
+ error << " Couldn't find #{name.pluralize(not_found_ids.size)} with #{key.to_s.pluralize(not_found_ids.size)} #{not_found_ids.join(', ')}." if not_found_ids
434
433
  raise RecordNotFound.new(error, name, key, ids)
435
434
  end
436
435
  end
@@ -472,7 +471,7 @@ module ActiveRecord
472
471
  )
473
472
  )
474
473
  relation = skip_query_cache_if_necessary do
475
- klass.with_connection do |c|
474
+ model.with_connection do |c|
476
475
  c.distinct_relation_for_primary_key(relation)
477
476
  end
478
477
  end
@@ -490,9 +489,9 @@ module ActiveRecord
490
489
  end
491
490
 
492
491
  def find_with_ids(*ids)
493
- raise UnknownPrimaryKey.new(@klass) if primary_key.nil?
492
+ raise UnknownPrimaryKey.new(model) if primary_key.nil?
494
493
 
495
- expects_array = if klass.composite_primary_key?
494
+ expects_array = if model.composite_primary_key?
496
495
  ids.first.first.is_a?(Array)
497
496
  else
498
497
  ids.first.is_a?(Array)
@@ -504,7 +503,7 @@ module ActiveRecord
504
503
 
505
504
  ids = ids.compact.uniq
506
505
 
507
- model_name = @klass.name
506
+ model_name = model.name
508
507
 
509
508
  case ids.size
510
509
  when 0
@@ -526,7 +525,7 @@ module ActiveRecord
526
525
  MSG
527
526
  end
528
527
 
529
- relation = if klass.composite_primary_key?
528
+ relation = if model.composite_primary_key?
530
529
  where(primary_key.zip(id).to_h)
531
530
  else
532
531
  where(primary_key => id)
@@ -574,7 +573,7 @@ module ActiveRecord
574
573
  result = relation.records
575
574
 
576
575
  if result.size == ids.size
577
- result.in_order_of(:id, ids.map { |id| @klass.type_for_attribute(primary_key).cast(id) })
576
+ result.in_order_of(:id, ids.map { |id| model.type_for_attribute(primary_key).cast(id) })
578
577
  else
579
578
  raise_record_not_found_exception!(ids, result.size, ids.size)
580
579
  end
@@ -639,7 +638,7 @@ module ActiveRecord
639
638
  end
640
639
 
641
640
  def ordered_relation
642
- if order_values.empty? && (implicit_order_column || !query_constraints_list.nil? || primary_key)
641
+ if order_values.empty? && (model.implicit_order_column || !model.query_constraints_list.nil? || primary_key)
643
642
  order(_order_columns.map { |column| table[column].asc })
644
643
  else
645
644
  self
@@ -649,11 +648,11 @@ module ActiveRecord
649
648
  def _order_columns
650
649
  oc = []
651
650
 
652
- oc << implicit_order_column if implicit_order_column
653
- oc << query_constraints_list if query_constraints_list
651
+ oc << model.implicit_order_column if model.implicit_order_column
652
+ oc << model.query_constraints_list if model.query_constraints_list
654
653
 
655
- if primary_key && query_constraints_list.nil?
656
- oc << primary_key
654
+ if model.primary_key && model.query_constraints_list.nil?
655
+ oc << model.primary_key
657
656
  end
658
657
 
659
658
  oc.flatten.uniq.compact
@@ -24,7 +24,7 @@ module ActiveRecord
24
24
  # the values.
25
25
  def other
26
26
  other = Relation.create(
27
- relation.klass,
27
+ relation.model,
28
28
  table: relation.table,
29
29
  predicate_builder: relation.predicate_builder
30
30
  )
@@ -84,7 +84,7 @@ module ActiveRecord
84
84
  def merge_select_values
85
85
  return if other.select_values.empty?
86
86
 
87
- if other.klass == relation.klass
87
+ if other.model == relation.model
88
88
  relation.select_values |= other.select_values
89
89
  else
90
90
  relation.select_values |= other.instance_eval do
@@ -96,12 +96,12 @@ module ActiveRecord
96
96
  def merge_preloads
97
97
  return if other.preload_values.empty? && other.includes_values.empty?
98
98
 
99
- if other.klass == relation.klass
99
+ if other.model == relation.model
100
100
  relation.preload_values |= other.preload_values unless other.preload_values.empty?
101
101
  relation.includes_values |= other.includes_values unless other.includes_values.empty?
102
102
  else
103
- reflection = relation.klass.reflect_on_all_associations.find do |r|
104
- r.class_name == other.klass.name
103
+ reflection = relation.model.reflect_on_all_associations.find do |r|
104
+ r.class_name == other.model.name
105
105
  end || return
106
106
 
107
107
  unless other.preload_values.empty?
@@ -117,7 +117,7 @@ module ActiveRecord
117
117
  def merge_joins
118
118
  return if other.joins_values.empty?
119
119
 
120
- if other.klass == relation.klass
120
+ if other.model == relation.model
121
121
  relation.joins_values |= other.joins_values
122
122
  else
123
123
  associations, others = other.joins_values.partition do |join|
@@ -136,7 +136,7 @@ module ActiveRecord
136
136
  def merge_outer_joins
137
137
  return if other.left_outer_joins_values.empty?
138
138
 
139
- if other.klass == relation.klass
139
+ if other.model == relation.model
140
140
  relation.left_outer_joins_values |= other.left_outer_joins_values
141
141
  else
142
142
  associations, others = other.left_outer_joins_values.partition do |join|
@@ -185,7 +185,7 @@ module ActiveRecord
185
185
 
186
186
  def replace_from_clause?
187
187
  relation.from_clause.empty? && !other.from_clause.empty? &&
188
- relation.klass.base_class == other.klass.base_class
188
+ relation.model.base_class == other.model.base_class
189
189
  end
190
190
  end
191
191
  end
@@ -59,8 +59,6 @@ module ActiveRecord
59
59
  def convert_to_id(value)
60
60
  if primary_key.is_a?(Array)
61
61
  primary_key.map do |attribute|
62
- next nil if value.nil?
63
-
64
62
  if attribute == "id"
65
63
  value.id_value
66
64
  else
@@ -37,7 +37,7 @@ module ActiveRecord
37
37
  if value.is_a?(Base)
38
38
  value.class
39
39
  elsif value.is_a?(Relation)
40
- value.klass
40
+ value.model
41
41
  end
42
42
  end
43
43
 
@@ -9,10 +9,11 @@ module ActiveRecord
9
9
  end
10
10
 
11
11
  if value.select_values.empty?
12
- if value.klass.composite_primary_key?
13
- raise ArgumentError, "Cannot map composite primary key #{value.klass.primary_key} to #{attribute.name}"
12
+ model = value.model
13
+ if model.composite_primary_key?
14
+ raise ArgumentError, "Cannot map composite primary key #{model.primary_key} to #{attribute.name}"
14
15
  else
15
- value = value.select(value.table[value.klass.primary_key])
16
+ value = value.select(value.table[model.primary_key])
16
17
  end
17
18
  end
18
19
 
@@ -77,6 +77,11 @@ module ActiveRecord
77
77
  return ["1=0"] if attributes.empty?
78
78
 
79
79
  attributes.flat_map do |key, value|
80
+ if key.is_a?(Array) && key.size == 1
81
+ key = key.first
82
+ value = value.flatten
83
+ end
84
+
80
85
  if key.is_a?(Array)
81
86
  queries = Array(value).map do |ids_set|
82
87
  raise ArgumentError, "Expected corresponding value for #{key} to be an Array" unless ids_set.is_a?(Array)
@@ -35,7 +35,7 @@ module ActiveRecord
35
35
  def nil?
36
36
  unless value_before_type_cast.is_a?(StatementCache::Substitute)
37
37
  value_before_type_cast.nil? ||
38
- (type.respond_to?(:subtype) || type.respond_to?(:normalizer)) && serializable? && value_for_database.nil?
38
+ type.respond_to?(:subtype) && serializable? && value_for_database.nil?
39
39
  end
40
40
  end
41
41