From f41808c71fb1a465e47cf4939b1e1c86695d5138 Mon Sep 17 00:00:00 2001 From: Roberto Miranda Date: Tue, 12 Mar 2024 13:33:52 +0000 Subject: [PATCH] Model.insert_all can accept an array of records with separate column names. --- activerecord/lib/active_record/insert_all.rb | 11 ++++++++-- activerecord/lib/active_record/persistence.rb | 4 ++-- activerecord/test/cases/insert_all_test.rb | 20 +++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/activerecord/lib/active_record/insert_all.rb b/activerecord/lib/active_record/insert_all.rb index 1b84f3d3015e0..b8bd64b194d6d 100644 --- a/activerecord/lib/active_record/insert_all.rb +++ b/activerecord/lib/active_record/insert_all.rb @@ -15,8 +15,15 @@ def execute(model, ...) end end - def initialize(model, connection, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil) - @model, @connection, @inserts = model, connection, inserts.map(&:stringify_keys) + def initialize(model, connection, inserts, on_duplicate:, update_only: nil, returning: nil, unique_by: nil, record_timestamps: nil, column_names: nil) + @model, @connection, @inserts = model, connection + + if column_names + @inserts = inserts.map { |values| column_names.map(&:to_s).zip(values).to_h } + else + @inserts = inserts.map(&:stringify_keys) + end + @on_duplicate, @update_only, @returning, @unique_by = on_duplicate, update_only, returning, unique_by @record_timestamps = record_timestamps.nil? ? model.record_timestamps : record_timestamps diff --git a/activerecord/lib/active_record/persistence.rb b/activerecord/lib/active_record/persistence.rb index 8a56a023b8a23..e1cd71f27d77e 100644 --- a/activerecord/lib/active_record/persistence.rb +++ b/activerecord/lib/active_record/persistence.rb @@ -172,8 +172,8 @@ def insert(attributes, returning: nil, unique_by: nil, record_timestamps: nil) # { id: 1, title: "Rework" }, # { id: 2, title: "Eloquent Ruby" } # ]) - def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil) - InsertAll.execute(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps) + def insert_all(attributes, returning: nil, unique_by: nil, record_timestamps: nil, column_names: nil) + InsertAll.execute(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by, record_timestamps: record_timestamps, column_names: column_names) end # Inserts a single record into the database in a single SQL INSERT diff --git a/activerecord/test/cases/insert_all_test.rb b/activerecord/test/cases/insert_all_test.rb index 1b30cefbdfcf3..aadb2621ffafa 100644 --- a/activerecord/test/cases/insert_all_test.rb +++ b/activerecord/test/cases/insert_all_test.rb @@ -64,6 +64,26 @@ def test_insert_all end end + def test_insert_all_with_column_names + assert_difference "Book.count", +10 do + column_names = [:name, :author_id] + books_data = [ + ["Rework", 1], + ["Patterns of Enterprise Application Architecture", 1], + ["Design of Everyday Things", 1], + ["Practical Object-Oriented Design in Ruby", 1], + ["Clean Code", 1], + ["Ruby Under a Microscope", 1], + ["The Principles of Product Development Flow", 1], + ["Peopleware", 1], + ["About Face", 1], + ["Eloquent Ruby", 1] + ] + + Book.insert_all(books_data, column_names: column_names) + end + end + def test_insert_all_should_handle_empty_arrays skip unless supports_insert_on_duplicate_update?