Skip to content

Commit bc760a5

Browse files
Fix upsert all that restore soft-deleted record accidentally
1 parent 7b96793 commit bc760a5

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

Diff for: lib/paranoia.rb

+26
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,21 @@ def paranoia_destroy_attributes
6464
def timestamp_attributes_with_current_time
6565
timestamp_attributes_for_update_in_model.each_with_object({}) { |attr,hash| hash[attr] = current_time_from_proper_timezone }
6666
end
67+
68+
def upsert_all(attributes, returning: nil, unique_by: nil)
69+
return super unless ActiveRecord::VERSION::STRING >= "7.0"
70+
71+
insert_all = ActiveRecord::InsertAll.new(
72+
self,
73+
attributes,
74+
on_duplicate: :update,
75+
returning: returning,
76+
unique_by: unique_by
77+
)
78+
insert_all.keys_including_timestamps.delete paranoia_column
79+
insert_all.updatable_columns.delete paranoia_column
80+
insert_all.execute
81+
end
6782
end
6883

6984
def paranoia_destroy
@@ -388,6 +403,17 @@ def deletion_time
388403
paranoia_column_value.acts_like?(:time) ? paranoia_column_value : deleted_at
389404
end
390405
end
406+
407+
class ActiveRecord::InsertAll
408+
private
409+
if ActiveRecord::VERSION::STRING >= "7.0"
410+
def verify_attributes(attributes)
411+
if keys_including_timestamps != attributes.keys.excluding(model.paranoia_column).to_set
412+
raise ArgumentError, "All objects being inserted must have the same keys"
413+
end
414+
end
415+
end
416+
end
391417
end
392418

393419
require 'paranoia/rspec' if defined? RSpec

Diff for: test/paranoia_test.rb

+18
Original file line numberDiff line numberDiff line change
@@ -1418,6 +1418,24 @@ def test_update_has_many_through_relation_delete_associations
14181418
assert_equal 2, employer.jobs.with_deleted.count
14191419
end
14201420

1421+
def test_upsert_all_on_soft_deleted_record
1422+
e1 = Employer.create(name: "e1")
1423+
e2 = Employer.create(name: "e2", deleted_at: Time.current)
1424+
assert_nil e1.deleted_at
1425+
assert e2.deleted_at != nil
1426+
1427+
Employer.upsert_all([
1428+
{ id: e1.id, name: "new_e1" },
1429+
{ id: e2.id, name: "new_e2" }
1430+
])
1431+
1432+
assert e1.reload.name == "new_e1"
1433+
assert e2.reload.name == "new_e2"
1434+
1435+
assert_nil e1.reload.deleted_at
1436+
assert e2.reload.deleted_at != nil
1437+
end
1438+
14211439
private
14221440
def get_featureful_model
14231441
FeaturefulModel.new(:name => "not empty")

0 commit comments

Comments
 (0)