Merge pull request #46406 from fatkodima/insert_all-sti

Fix `insert_all`/`upsert_all` to handle STI
This commit is contained in:
Jean Boussier 2022-11-03 22:59:17 +01:00 committed by GitHub
commit 029a603d66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 33 additions and 2 deletions

View File

@ -8,7 +8,7 @@ module ActiveRecord
attr_reader :on_duplicate, :update_only, :returning, :unique_by, :update_sql
def initialize(model, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil)
@model, @connection, @inserts = model, model.connection, inserts
@model, @connection, @inserts = model, model.connection, inserts.map(&:stringify_keys)
@on_duplicate, @update_only, @returning, @unique_by = on_duplicate, update_only, returning, unique_by
@record_timestamps = record_timestamps.nil? ? model.record_timestamps : record_timestamps
@ -18,8 +18,9 @@ module ActiveRecord
if @inserts.empty?
@keys = []
else
resolve_sti
resolve_attribute_aliases
@keys = @inserts.first.keys.map(&:to_s)
@keys = @inserts.first.keys
end
configure_on_duplicate_update_logic
@ -99,6 +100,15 @@ module ActiveRecord
attributes.keys.any? { |attribute| model.attribute_alias?(attribute) }
end
def resolve_sti
return if model.descends_from_active_record?
sti_type = model.sti_name
@inserts = @inserts.map do |insert|
insert.reverse_merge(model.inheritance_column.to_s => sti_type)
end
end
def resolve_attribute_aliases
return unless has_attribute_aliases?(@inserts.first)

View File

@ -3,6 +3,7 @@
require "cases/helper"
require "models/author"
require "models/book"
require "models/category"
require "models/cart"
require "models/developer"
require "models/ship"
@ -282,6 +283,26 @@ class InsertAllTest < ActiveRecord::TestCase
end
end
def test_insert_all_and_upsert_all_with_sti
assert_difference -> { Category.count }, 2 do
SpecialCategory.insert_all [{ name: "First" }, { name: "Second", type: nil }]
end
first, second = Category.last(2)
assert_equal "SpecialCategory", first.type
assert_nil second.type
if supports_insert_on_duplicate_update?
SpecialCategory.upsert_all [{ id: 103, name: "First" }, { id: 104, name: "Second", type: nil }]
category3 = Category.find(103)
assert_equal "SpecialCategory", category3.type
category4 = Category.find(104)
assert_nil category4.type
end
end
def test_upsert_logs_message_including_model_name
skip unless supports_insert_on_duplicate_update?