Skip to content

Commit f68cb23

Browse files
authored
fix: restore has_one with scope (#551)
* test: simplify HasOneWithScope relation config * test: add has_one restore by accident test case * test: imporove has_one_with_scope_missed
1 parent de74493 commit f68cb23

File tree

2 files changed

+52
-7
lines changed

2 files changed

+52
-7
lines changed

Diff for: lib/paranoia.rb

+12-7
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,16 @@ def timestamp_attributes_with_current_time
210210
timestamp_attributes_for_update_in_model.each_with_object({}) { |attr,hash| hash[attr] = current_time_from_proper_timezone }
211211
end
212212

213+
def paranoia_find_has_one_target(association)
214+
association_foreign_key = association.options[:through].present? ? association.klass.primary_key : association.foreign_key
215+
association_find_conditions = { association_foreign_key => self.id }
216+
association_find_conditions[association.type] = self.class.name if association.type
217+
218+
scope = association.klass.only_deleted.where(association_find_conditions)
219+
scope = scope.merge(association.scope) if association.scope
220+
scope.first
221+
end
222+
213223
# restore associated records that have been soft deleted when
214224
# we called #destroy
215225
def restore_associated_records(recovery_window_range = nil)
@@ -233,13 +243,8 @@ def restore_associated_records(recovery_window_range = nil)
233243
end
234244

235245
if association_data.nil? && association.macro.to_s == "has_one"
236-
association_class = association.klass
237-
if association_class.paranoid?
238-
association_foreign_key = association.options[:through].present? ? association.klass.primary_key : association.foreign_key
239-
association_find_conditions = { association_foreign_key => self.id }
240-
association_find_conditions[association.type] = self.class.name if association.type
241-
242-
association_class.only_deleted.where(association_find_conditions).first
246+
if association.klass.paranoid?
247+
paranoia_find_has_one_target(association)
243248
.try!(:restore, recursive: true, :recovery_window_range => recovery_window_range)
244249
end
245250
end

Diff for: test/paranoia_test.rb

+40
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def setup!
5454
'empty_paranoid_models' => 'deleted_at DATETIME',
5555
'paranoid_has_one_throughs' => 'paranoid_has_through_restore_parent_id INTEGER NOT NULL, empty_paranoid_model_id INTEGER NOT NULL, deleted_at DATETIME',
5656
'paranoid_has_many_throughs' => 'paranoid_has_through_restore_parent_id INTEGER NOT NULL, empty_paranoid_model_id INTEGER NOT NULL, deleted_at DATETIME',
57+
'paranoid_has_one_with_scopes' => 'deleted_at DATETIME, kind STRING, paranoid_has_one_with_scope_id INTEGER',
5758
}.each do |table_name, columns_as_sql_string|
5859
ActiveRecord::Base.connection.execute "CREATE TABLE #{table_name} (id INTEGER NOT NULL PRIMARY KEY, #{columns_as_sql_string})"
5960
end
@@ -1223,6 +1224,37 @@ def test_counter_cache_column_on_restore
12231224
end
12241225
end
12251226

1227+
def test_has_one_with_scope_missed
1228+
parent = ParanoidHasOneWithScope.create
1229+
gamma = ParanoidHasOneWithScope.create(kind: :gamma, paranoid_has_one_with_scope: parent) # this has to be first
1230+
alpha = ParanoidHasOneWithScope.create(kind: :alpha, paranoid_has_one_with_scope: parent)
1231+
beta = ParanoidHasOneWithScope.create(kind: :beta, paranoid_has_one_with_scope: parent)
1232+
1233+
parent.destroy
1234+
assert !gamma.reload.destroyed?
1235+
gamma.destroy
1236+
assert_equal 0, ParanoidHasOneWithScope.count # all destroyed
1237+
parent.reload # we unload associations
1238+
parent.restore(recursive: true)
1239+
1240+
assert_equal "alpha", parent.alpha&.kind, "record was not restored"
1241+
assert_equal "beta", parent.beta&.kind, "record was not restored"
1242+
assert_nil parent.gamma, "record was incorrectly restored"
1243+
end
1244+
1245+
def test_has_one_with_scope_not_restored
1246+
parent = ParanoidHasOneWithScope.create
1247+
gamma = ParanoidHasOneWithScope.create(kind: :gamma, paranoid_has_one_with_scope: parent)
1248+
parent.destroy
1249+
assert_equal 1, ParanoidHasOneWithScope.count # gamma not deleted
1250+
gamma.destroy
1251+
parent.reload # we unload associations
1252+
parent.restore(recursive: true)
1253+
1254+
assert gamma.reload.deleted?, "the record was incorrectly restored"
1255+
assert_equal 1, ParanoidHasOneWithScope.count # gamma deleted
1256+
end
1257+
12261258
private
12271259
def get_featureful_model
12281260
FeaturefulModel.new(:name => "not empty")
@@ -1627,3 +1659,11 @@ class ParanoidHasManyThrough < ActiveRecord::Base
16271659
belongs_to :paranoid_has_through_restore_parent
16281660
belongs_to :empty_paranoid_model, dependent: :destroy
16291661
end
1662+
1663+
class ParanoidHasOneWithScope < ActiveRecord::Base
1664+
acts_as_paranoid
1665+
has_one :alpha, -> () { where(kind: :alpha) }, class_name: "ParanoidHasOneWithScope", dependent: :destroy
1666+
has_one :beta, -> () { where(kind: :beta) }, class_name: "ParanoidHasOneWithScope", dependent: :destroy
1667+
has_one :gamma, -> () { where(kind: :gamma) }, class_name: "ParanoidHasOneWithScope"
1668+
belongs_to :paranoid_has_one_with_scope
1669+
end

0 commit comments

Comments
 (0)