Skip to content

Commit

Permalink
Merge branch 'rails3.2'
Browse files Browse the repository at this point in the history
Conflicts:
	rails3_acts_as_paranoid.gemspec
  • Loading branch information
goncalossilva committed Dec 9, 2012
2 parents 5f691e7 + 4b54297 commit cbca2cf
Show file tree
Hide file tree
Showing 9 changed files with 139 additions and 60 deletions.
2 changes: 1 addition & 1 deletion README.markdown
Expand Up @@ -33,7 +33,7 @@ The values shown are the defaults. While *column* can be anything (as long as it
- `time` or
- `string`

If your column type is a `string`, you can also specify which value to use when marking an object as deleted by passing `:deleted_value` (default is "deleted").
If your column type is a `string`, you can also specify which value to use when marking an object as deleted by passing `:deleted_value` (default is "deleted"). Any records with a non-matching value in this column will be treated normally (ie: not deleted).

### Filtering

Expand Down
6 changes: 5 additions & 1 deletion Rakefile
Expand Up @@ -17,7 +17,11 @@ desc 'Test the rails3_acts_as_paranoid plugin.'
Rake::TestTask.new(:test) do |t|
t.libs << 'lib'
t.libs << 'test'
t.pattern = 'test/**/test_*.rb'

test_files = FileList['test/**/test_*.rb']
test_files.exclude('test/test_helper.rb')
t.test_files = test_files

t.verbose = true
end

Expand Down
20 changes: 11 additions & 9 deletions lib/acts_as_paranoid/associations.rb
Expand Up @@ -14,15 +14,17 @@ def belongs_to_with_deleted(target, options = {})

if with_deleted
result.options[:with_deleted] = with_deleted
class_eval <<-RUBY, __FILE__, __LINE__
def #{target}_with_unscoped(*args)
association = association(:#{target})
return nil if association.options[:polymorphic] && association.klass.nil?
return #{target}_without_unscoped(*args) unless association.klass.paranoid?
association.klass.with_deleted.scoping { #{target}_without_unscoped(*args) }
end
alias_method_chain :#{target}, :unscoped
RUBY
unless method_defined? "#{target}_with_unscoped"
class_eval <<-RUBY, __FILE__, __LINE__
def #{target}_with_unscoped(*args)
association = association(:#{target})
return nil if association.options[:polymorphic] && association.klass.nil?
return #{target}_without_unscoped(*args) unless association.klass.paranoid?
association.klass.with_deleted.scoping { #{target}_without_unscoped(*args) }
end
alias_method_chain :#{target}, :unscoped
RUBY
end
end

result
Expand Down
40 changes: 31 additions & 9 deletions lib/acts_as_paranoid/core.rb
Expand Up @@ -22,7 +22,11 @@ def with_deleted
end

def only_deleted
without_paranoid_default_scope.where("#{paranoid_column_reference} IS NOT ?", nil)
if string_type_with_deleted_value?
without_paranoid_default_scope.where("#{paranoid_column_reference} IS ?", paranoid_configuration[:deleted_value])
else
without_paranoid_default_scope.where("#{paranoid_column_reference} IS NOT ?", nil)
end
end

def delete_all!(conditions = nil)
Expand All @@ -34,7 +38,17 @@ def delete_all(conditions = nil)
end

def paranoid_default_scope_sql
self.scoped.table[paranoid_column].eq(nil).to_sql
if string_type_with_deleted_value?
self.scoped.table[paranoid_column].eq(nil).
or(self.scoped.table[paranoid_column].not_eq(paranoid_configuration[:deleted_value])).
to_sql
else
self.scoped.table[paranoid_column].eq(nil).to_sql
end
end

def string_type_with_deleted_value?
paranoid_column_type == :string && !paranoid_configuration[:deleted_value].nil?
end

def paranoid_column
Expand Down Expand Up @@ -67,6 +81,10 @@ def without_paranoid_default_scope
end
end

def persisted?
!(new_record? || @destroyed)
end

def paranoid_value
self.send(self.class.paranoid_column)
end
Expand All @@ -75,18 +93,20 @@ def destroy!
with_transaction_returning_status do
run_callbacks :destroy do
destroy_dependent_associations!
self.class.delete_all!(self.class.primary_key.to_sym => self.id)
# Handle composite keys, otherwise we would just use `self.class.primary_key.to_sym => self.id`.
self.class.delete_all!(Hash[[Array(self.class.primary_key), Array(self.id)].transpose])
self.paranoid_value = self.class.delete_now_value
freeze
end
end
end

def destroy
if paranoid_value.nil?
if !deleted?
with_transaction_returning_status do
run_callbacks :destroy do
self.class.delete_all(self.class.primary_key.to_sym => self.id)
# Handle composite keys, otherwise we would just use `self.class.primary_key.to_sym => self.id`.
self.class.delete_all(Hash[[Array(self.class.primary_key), Array(self.id)].transpose])
self.paranoid_value = self.class.delete_now_value
self
end
Expand Down Expand Up @@ -117,7 +137,7 @@ def recover_dependent_associations(window, options)
next unless reflection.klass.paranoid?

scope = reflection.klass.only_deleted

# Merge in the association's scope
scope = scope.merge(association(reflection.name).association_scope)

Expand All @@ -132,13 +152,13 @@ def recover_dependent_associations(window, options)
end
end
end

def destroy_dependent_associations!
self.class.dependent_associations.each do |reflection|
next unless reflection.klass.paranoid?

scope = reflection.klass.only_deleted

# Merge in the association's scope
scope = scope.merge(association(reflection.name).association_scope)

Expand All @@ -149,8 +169,10 @@ def destroy_dependent_associations!
end

def deleted?
!paranoid_value.nil?
!(paranoid_value.nil? ||
(self.class.string_type_with_deleted_value? && paranoid_value != self.class.delete_now_value))
end

alias_method :destroyed?, :deleted?

private
Expand Down
4 changes: 3 additions & 1 deletion lib/acts_as_paranoid/validations.rb
Expand Up @@ -18,7 +18,9 @@ def validate_each(record, attribute, value)
end

relation = build_relation(finder_class, table, attribute, value)
relation = relation.and(table[finder_class.primary_key.to_sym].not_eq(record.send(:id))) if record.persisted?
[Array(finder_class.primary_key), Array(record.send(:id))].transpose.each do |pk_key, pk_value|
relation = relation.and(table[pk_key.to_sym].not_eq(pk_value))
end if record.persisted?

Array.wrap(options[:scope]).each do |scope_item|
scope_value = record.send(scope_item)
Expand Down
2 changes: 1 addition & 1 deletion rails3_acts_as_paranoid.gemspec
Expand Up @@ -10,7 +10,7 @@ Gem::Specification.new do |s|
s.rubyforge_project = s.name

s.required_rubygems_version = ">= 1.3.6"

s.add_dependency "activerecord", "~> 3.2"

s.files = Dir["{lib}/**/*.rb", "LICENSE", "*.markdown"]
Expand Down
74 changes: 39 additions & 35 deletions test/test_associations.rb
Expand Up @@ -8,7 +8,7 @@ def test_removal_with_associations
paranoid_company_2 = ParanoidDeleteCompany.create! :name => "ParanoidDestroyCompany #1"
paranoid_company_1.paranoid_products.create! :name => "ParanoidProduct #1"
paranoid_company_2.paranoid_products.create! :name => "ParanoidProduct #2"

assert_equal 1, ParanoidDestroyCompany.count
assert_equal 1, ParanoidDeleteCompany.count
assert_equal 2, ParanoidProduct.count
Expand All @@ -18,13 +18,13 @@ def test_removal_with_associations
assert_equal 1, ParanoidProduct.count
assert_equal 1, ParanoidDestroyCompany.with_deleted.count
assert_equal 2, ParanoidProduct.with_deleted.count

ParanoidDestroyCompany.with_deleted.first.destroy!
assert_equal 0, ParanoidDestroyCompany.count
assert_equal 1, ParanoidProduct.count
assert_equal 0, ParanoidDestroyCompany.with_deleted.count
assert_equal 1, ParanoidProduct.with_deleted.count

ParanoidDeleteCompany.with_deleted.first.destroy!
assert_equal 0, ParanoidDeleteCompany.count
assert_equal 0, ParanoidProduct.count
Expand All @@ -40,7 +40,7 @@ def test_belongs_to_with_deleted
assert_equal paranoid_time, paranoid_has_many_dependant.paranoid_time_with_deleted

paranoid_time.destroy

assert_nil paranoid_has_many_dependant.paranoid_time(true)
assert_equal paranoid_time, paranoid_has_many_dependant.paranoid_time_with_deleted(true)
end
Expand All @@ -53,7 +53,7 @@ def test_belongs_to_polymorphic_with_deleted
assert_equal paranoid_time, paranoid_has_many_dependant.paranoid_time_polymorphic_with_deleted

paranoid_time.destroy

assert_nil paranoid_has_many_dependant.paranoid_time(true)
assert_equal paranoid_time, paranoid_has_many_dependant.paranoid_time_polymorphic_with_deleted(true)
end
Expand All @@ -66,7 +66,7 @@ def test_belongs_to_nil_polymorphic_with_deleted
assert_nil paranoid_has_many_dependant.paranoid_time_polymorphic_with_deleted

paranoid_time.destroy

assert_nil paranoid_has_many_dependant.paranoid_time(true)
assert_nil paranoid_has_many_dependant.paranoid_time_polymorphic_with_deleted(true)
end
Expand All @@ -93,111 +93,107 @@ def test_only_find_associated_records_when_finding_with_paranoid_deleted
parent = ParanoidBelongsDependant.create
child = ParanoidHasManyDependant.create
parent.paranoid_has_many_dependants << child

unrelated_parent = ParanoidBelongsDependant.create
unrelated_child = ParanoidHasManyDependant.create
unrelated_parent.paranoid_has_many_dependants << unrelated_child

child.destroy
assert_paranoid_deletion(child)

assert_equal [child], parent.paranoid_has_many_dependants.with_deleted.to_a
end

def test_cannot_find_a_paranoid_deleted_many_many_association
left = ParanoidManyManyParentLeft.create
right = ParanoidManyManyParentRight.create
left.paranoid_many_many_parent_rights << right

child = left.paranoid_many_many_children.first

left.paranoid_many_many_parent_rights.delete(right)

left.reload

assert_equal [], left.paranoid_many_many_children, "Linking objects not deleted"
assert_equal [], left.paranoid_many_many_parent_rights, "Associated objects not unlinked"
assert_equal right, ParanoidManyManyParentRight.find(right.id), "Associated object deleted"
end

def test_cannot_find_a_paranoid_destroyed_many_many_association
left = ParanoidManyManyParentLeft.create
right = ParanoidManyManyParentRight.create
left.paranoid_many_many_parent_rights << right

child = left.paranoid_many_many_children.first

left.paranoid_many_many_parent_rights.destroy(right)

left.reload

assert_equal [], left.paranoid_many_many_children, "Linking objects not deleted"
assert_equal [], left.paranoid_many_many_parent_rights, "Associated objects not unlinked"
assert_equal right, ParanoidManyManyParentRight.find(right.id), "Associated object deleted"
end

def test_cannot_find_a_has_many_through_object_when_its_linking_object_is_paranoid_destroyed
left = ParanoidManyManyParentLeft.create
right = ParanoidManyManyParentRight.create
left.paranoid_many_many_parent_rights << right

child = left.paranoid_many_many_children.first

child.destroy

left.reload

assert_equal [], left.paranoid_many_many_parent_rights, "Associated objects not deleted"
end

def test_cannot_find_a_paranoid_deleted_model
model = ParanoidBelongsDependant.create
model.destroy

assert_raises ActiveRecord::RecordNotFound do
ParanoidBelongsDependant.find(model.id)
end
end

def test_bidirectional_has_many_through_association_clear_is_paranoid
left = ParanoidManyManyParentLeft.create
right = ParanoidManyManyParentRight.create
left.paranoid_many_many_parent_rights << right

child = left.paranoid_many_many_children.first
assert_equal left, child.paranoid_many_many_parent_left, "Child's left parent is incorrect"
assert_equal right, child.paranoid_many_many_parent_right, "Child's right parent is incorrect"

left.paranoid_many_many_parent_rights.clear

assert_paranoid_deletion(child)
end

def test_bidirectional_has_many_through_association_destroy_is_paranoid
left = ParanoidManyManyParentLeft.create
right = ParanoidManyManyParentRight.create
left.paranoid_many_many_parent_rights << right

child = left.paranoid_many_many_children.first
assert_equal left, child.paranoid_many_many_parent_left, "Child's left parent is incorrect"
assert_equal right, child.paranoid_many_many_parent_right, "Child's right parent is incorrect"

left.paranoid_many_many_parent_rights.destroy(right)

assert_paranoid_deletion(child)
end

def test_bidirectional_has_many_through_association_delete_is_paranoid
left = ParanoidManyManyParentLeft.create
right = ParanoidManyManyParentRight.create
left.paranoid_many_many_parent_rights << right

child = left.paranoid_many_many_children.first
assert_equal left, child.paranoid_many_many_parent_left, "Child's left parent is incorrect"
assert_equal right, child.paranoid_many_many_parent_right, "Child's right parent is incorrect"

left.paranoid_many_many_parent_rights.delete(right)

assert_paranoid_deletion(child)
end

Expand All @@ -208,4 +204,12 @@ def test_belongs_to_on_normal_model_is_paranoid
assert not_paranoid.save
assert_not_nil not_paranoid.paranoid_time
end

def test_double_belongs_to_with_deleted
not_paranoid = DoubleHasOneNotParanoid.create
not_paranoid.paranoid_time = ParanoidTime.create

assert not_paranoid.save
assert_not_nil not_paranoid.paranoid_time
end
end

0 comments on commit cbca2cf

Please sign in to comment.